<?php

namespace CouponsPlus\App\Coupon\Tree\ItemSetsToDiscount;

use CouponsPlus\App\Conditions\ItemsSet;
use CouponsPlus\Original\Collections\Collection;
use CouponsPlus\App\Coupon\Tree\Cart\CartModifier;
use CouponsPlus\App\Coupon\Tree\Cart\CartModifiedException;
use CouponsPlus\App\Coupon\Tree\Sets\Factories\PriceSorterFactory;
use CouponsPlus\App\Coupon\Tree\Abilities\ItemsInCartFinderStrategy;
use WC_Cart;
use Exception;

use function CouponsPlus\App\Coupon\Tree\TestableHooks\usingSorter;

/**
 * Will get the eligible items from the cart using $cartItemsResolverStrategy
 * and may add them to the cart if possible.
 */
class CartItemsToDiscountFinder
{
    protected ItemsInCartFinderStrategy $productsInCartFinderStrategy;
    protected PriceSorterFactory $priceSorterFactory;

    public function __construct(
        ItemsInCartFinderStrategy $productsInCartFinderStrategy,
        PriceSorterFactory $priceSorterFactory
    ) {
        $this->productsInCartFinderStrategy = $productsInCartFinderStrategy;
        $this->priceSorterFactory = $priceSorterFactory;
    }

    /**
     * @return ItemsSetToDiscountCollection of ItemsSetToDiscount
     * @throws CartModifiedException|Exception
     */
    public function findItemsToDiscount(ItemsSet $itemsSetPassedToThisOffer
    ): ItemsSetToDiscountCollection {
        /**
         * So we have 3 POSSIBLE OUTCOMES
         *
         * we have none,
         * we have incomplete: we have some of the required items, but not all
         * we have all
         */
        $setsToDiscount = new ItemsSetToDiscountCollection;

        /** @var ProductToDiscount $productToDiscount */
            foreach ($this->productsInCartFinderStrategy->getProductsToDiscount()->asArray() as $productToDiscount) {
            $testableComposite = $this->productsInCartFinderStrategy->getFinder(
                $productToDiscount
            );

            $items = usingSorter($this->priceSorterFactory->create(PriceSorterFactory::CHEAPEST), function () use ($productToDiscount, $setsToDiscount, $itemsSetPassedToThisOffer, $testableComposite) : ItemsSet {
                $all = $testableComposite
                    ->filterSet(
                    // from all cart items
                        ItemsSet::createFromAllEligibleCartItemsDuringDiscovery()
                            // without the items passed to this offer (the "buy" part of the BOGO)
                            ->without($itemsSetPassedToThisOffer)
                            // without the items already selected for discount
                            ->without($setsToDiscount->flattenedItems())
                    );

                // a new variable here for debugging (breakpoints)
                $quantityDiscount = $productToDiscount->getDiscountOptions()->quantity;

                if (is_int($quantityDiscount)) {
                    return $all->selectQuantityOrdered('maximum', $quantityDiscount);
                }
                // this is a mapped object with any, fixed, max, etc
                // currently we only support any so let's do that
                // and js like that we should support discounting any number of specific products
                return $all->selectQuantityOrdered('minimum', 1);
            });

            // let's add them to the set, regardless of if we have all the required quantity or not (because empty checks may be used by code somewhere else)
            $setsToDiscount->addSet(
                new ItemsSetToDiscount(
                    $items,
                    $productToDiscount
                )
            );

        }

        return $setsToDiscount;
    }
}