<?php

namespace CouponsPlus\App\Coupon\Tree\Finders;

use CouponsPlus\App\Conditions\Abilities\TestableComposite;
use CouponsPlus\App\Conditions\ItemsSet;
use CouponsPlus\App\Coupon\CartComponentsSet;
use CouponsPlus\App\Coupon\Tree\Abilities\Branch;
use CouponsPlus\App\Coupon\Tree\Abilities\CardData;
use CouponsPlus\App\Coupon\Tree\Abilities\FindableOffersFromBranch;
use CouponsPlus\App\Coupon\Tree\Abilities\WithIdentifier;
use CouponsPlus\App\Coupon\Tree\Finders\FindableOffersFromBranchComposite;
use CouponsPlus\App\Coupon\Tree\Finders\Sets\OffersDataSet;
use CouponsPlus\App\Coupon\Tree\Offeritemssetfilters\DiscountItemsFilter;
use CouponsPlus\App\Coupon\Tree\Offeritemssetfilters\NotExcludedPassThroughItemsFilter;
use CouponsPlus\App\Coupon\Tree\Offeritemssetfilters\PassThroughItemsFilter;
use CouponsPlus\App\Factory\Abilities\OverloadableFactory;
use CouponsPlus\App\Offers\BuiltIn\BundlePrice;
use CouponsPlus\App\Offers\BuiltIn\ExtraProduct;
use CouponsPlus\App\Offers\BuiltIn\ShippingDiscount;
use CouponsPlus\Original\Collections\Collection;

/**
 * 
 *
 *
 * NOT USED CURRENTLY!
 *
 *
 *
 * 
 */
/**
 * Only sets the cart items required for the offers. 
 *
 * For example: we have been passed 10 cart items but the Discount offer has a limit of 2, 
 * then just set those 2 items instead of the whole 10 so that 
 * the other 8 may be used somewhere else if needed.
 * 
 */
class ItemsSetOfOffersOptimizerOffersFinderFromBranch extends FindableOffersFromBranchComposite implements FindableOffersFromBranch, OverloadableFactory
{
    /** @param Branch $value */
    public function canCreate($value): bool
    {
        return $this->findableOffersFromBranch->canCreate($value);            
    } 

    protected function getFiltersForOffers(Collection $offerDatas) : Collection
    {
        /**
         * Hard-coded for now, sorry. These dependencies should be injected...
         */
        static $filters = new Collection([
            new DiscountItemsFilter,
            new NotExcludedPassThroughItemsFilter(ExtraProduct::TYPE),
            new NotExcludedPassThroughItemsFilter(ShippingDiscount::TYPE),
            new PassThroughItemsFilter(BundlePrice::TYPE)
        ]);

        (object) $offerIds = $offerDatas->map(function(CardData $cardData) : string {
            return $cardData->getType(); 
        });

        return $filters->filter(function(WithIdentifier $filter) use($offerIds) : bool {
            return $offerIds->contain($filter->getIdentifier());
        });
    }
    
    public function findOffers(ItemsSet $itemsSet, Branch $branch): CartComponentsSet
    {
        /** @var OffersDataSet */
        (object) $offersSet = $this->findableOffersFromBranch->findOffers(...func_get_args());
        (object) $offerFilters = $this->getFiltersForOffers($offersSet->getItems());

        if ($offerFilters->haveNone()) {
            return $itemsSet;
        }

        (object) $itemsSet = new ItemsSet([]);

        /** @var TestableComposite $itemsSetFilterForOffer */
        foreach ($this->getFiltersForOffers($offersSet->getItems()) as $itemsSetFilterForOffer) {
            $itemsSet->addItems($itemsSetFilterForOffer->filterSet($itemsSet)->without($itemsSet));
        }

        return $offersSet;
    } 
}