<?php

namespace CouponsPlus\App\Coupon\Tree\Factories;

use CouponsPlus\App\Coupon\Tree\Branch;
use CouponsPlus\App\Coupon\Tree\NodeData;
use CouponsPlus\App\Coupon\Tree\GroveData;
use CouponsPlus\App\Coupon\Tree\Abilities\CardData;

/**
 * [Non-destructive, shallow] (creates a new instance (shallow clone))
 *
 * So given a GroveData object, it'll split trees with branch offers that have multiple offers into multiple trees with single offers in each branch.
 *
 * Example: 1 tree has a branch with a discount and BuyXGetY offer, this will create 2 trees, one with the discount offer branch and one with the BuyXGetY offer branch.
 *
 * This is because each offer requires different filtering and processing of the filtered items. E.g.: bogos will request the most expensive items, while discounts will request the cheapest. There's more than just this simple example. So don't remove it just because you think it's unnecessary.
 *
 * Currently only supports root trees, multi-offers in tiered branches are left as is because currently we don't support bogos in tiers so..
 */
class MultiOffersBranchNodeVirtualizer
{
    protected GroveData $groveData;

    public function __construct(GroveData $groveData)
    {
        $this->groveData = $groveData;
    }

    public function virtualize(): GroveData
    {
        (object) $virtualizedGrove = clone $this->groveData;

        /** @var NodeData $tree */
        foreach ($this->groveData->getTrees()->asArray() as $tree) {
            if ($tree->getBranch()->is('offers') && $tree->getBranch()->getChildren()->haveMoreThan(1)) {
                // multi-offers so split it.
                // the actual node id is kept the same for tracking purposes (to know that these share the same origin)
                (object) $trees = $tree->getBranch()->getChildren()->getValues()->map(function (CardData $offerData, int $index) use ($tree) : NodeData {
                    (object) $virtualizedTree = new NodeData(
                        $tree->getTestable(), // literally the same
                        new Branch('offers', [$offerData]),
                    );

                    $virtualizedTree->setVirtualInstanceIndex($index);

                    return $virtualizedTree;
                });

                // now that we have the trees, lets replace the original tree with these new ones.
                $virtualizedGrove->replaceTree($tree, $trees);
                // that's basically it.
            }
        }

        return $virtualizedGrove;
    }
}