<?php

namespace CouponsPlus\App\Coupon\Tree\Finders;

use WC_Coupon;
use CouponsPlus\Original\Environment\Env;
use CouponsPlus\App\Factory\FactoryOverloader;
use CouponsPlus\Original\Collections\Collection;
use CouponsPlus\App\Coupon\Tree\Testable\PathRecorderFilterableSet;
use CouponsPlus\App\Coupon\Tree\Testable\ItemSetUsingBranchFilterableSet;
use CouponsPlus\App\Coupon\Tree\Factories\MultiOffersBranchNodeVirtualizer;
use CouponsPlus\App\Coupon\Tree\Testable\ItemsSetSorterFromBranchFilterableSet;
use CouponsPlus\App\Coupon\Tree\Factories\ConditionFilterOrOfferFromDataFactory;
use CouponsPlus\App\Coupon\Tree\OfferItemsSetFilters\OffersItemsSetResolverFromData;

class ProductionGroveOffersDataFinderFactory
{
    private WC_Coupon $coupon;

    public function __construct(WC_Coupon $coupon)
    {
        $this->coupon = $coupon;
    } 

    public function create(string $groveJsonSource, string $partialRelationsSource = '[]', int $version = 0) : GroveOffersDataFinder
    {
        $itemsSetFiltererFromDataFactory = new ItemsSetFiltererFromDataFactory;
        $itemsSetFiltererFromData = $itemsSetFiltererFromDataFactory->create($this->coupon);

        (object) $nodeOffersFinder = new RuntimeNodeOffersFinder(
            new PathRecorderFilterableSet(
                new ItemSetUsingBranchFilterableSet(
                    new ItemsSetSorterFromBranchFilterableSet(
                        $itemsSetFiltererFromData
                    )
                )
            ),
            new EmptyOffersOnEmptyItemsSetOffersFinderFromBranch(
                new RuntimeOffersFinderFromBranch(
                    new FactoryOverloader(
                        new Collection(apply_filters(
                            /**
                             * Register additional FindableOffersFromBranch implementations here.
                             *
                             * Coupons+ Pro for example, registers the very complex TieredBranchRuntimeOffersFinder
                             * that has several algorithms for handling tiered branches
                             */
                            Env::getWithPrefix('Grove.Offers.Finders'),
                            [
                                    new LeavesBranchRuntimeOffersFinder(
                                        new OffersItemsSetResolverFromData(new ConditionFilterOrOfferFromDataFactory($this->coupon))),

                                ],
                                $itemsSetFiltererFromData
                            )
                        )
                    )
                )
          )
        );

        do_action(Env::getWithPrefix('Grove.Offers.Finders.Initialized'), $nodeOffersFinder);

        /** @noinspection JsonEncodingApiUsageInspection */
        (object) $dataStructureFromJsonFactory = (new ProductionDataStructureFromJSONFactory())->create($partialRelationsSource);

        (object) $treesVirtualizer = new MultiOffersBranchNodeVirtualizer(
            $dataStructureFromJsonFactory->createFromSource($groveJsonSource, $version)
        );

        return new GroveOffersDataFinder(
            $treesVirtualizer->virtualize(),
            $nodeOffersFinder
        );
    }
}