<?php

namespace CouponsPlus\App\Coupon\Tree;

use CouponsPlus\App\Coupon\Tree\Abilities;
use CouponsPlus\App\Coupon\Tree\Abilities\Branch;
use CouponsPlus\Original\Characters\StringManager;
use CouponsPlus\Original\Collections\Collection;
use JsonSerializable;
use CouponsPlus\App\Coupon\Tree\Abilities\NodeData;
use CouponsPlus\App\Coupon\Tree\Abilities\TestableData;

class TestableGroupData implements Abilities\TestableGroupData, JsonSerializable
{
    protected ?TestableGroupData $parent = null;
    protected ?NodeData $node = null;
    protected ?string $id;

    /** @property StringManager */
    private $type;
    /** @property StringManager */
    private $mode;
    /** @property Collection */
    private $children;

    public function __construct(string $type, string $mode, array $children, string $id = null)
    {
        $this->id = $id;
        $this->type = new StringManager($type);
        $this->mode = new StringManager($mode);
        $this->children = new Collection($children);
        $this->children->forEvery(function (Abilities\WithTestableParent $child) {
            $child->setParent($this);
        });

    }

    /**
     * @param TestableGroupData $parent
     */
    public function setParent($parent): void
    {
        $this->parent = $parent;
    }

    public function getParent(): ?TestableGroupData
    {
        return $this->parent;
    }

    public function setNode(NodeData $nodeData): void
    {
        $this->node = $nodeData;
    }

    public function getNode(): ?NodeData
    {
        return $this->node;
    }

    public function getId(): string
    {
        return (string) $this->id;
    }

    public function getType(): StringManager
    {
        return $this->type;
    }

    public function getMode(): StringManager
    {
        return $this->mode;
    }

    public function getChildren(): Collection
    {
        return $this->children;
    }

    #[\ReturnTypeWillChange]
    public function jsonSerialize() : array
    {
        return get_object_vars($this);
    }

    /**
     * Only when this is:
     *     1) a context
     *     2) test mode is 'filter'
     */
    public function getIntersectionFilters() : Collection
    {
        if ($this->getType()->isNot('context')) {
            return new Collection([]);
        }

        if ($this->getMode()->isNot('filter')) {
            return new Collection([]);
        }

        return $this->children->filter(
        /**
         * @param Abilities\TestableData|Abilities\TestableGroupData $testableData
         * @return bool
         */
        function($testableData) {
            return $testableData->getType()->is('context');
        });
    }

    public function canFilterItems(): bool
    {
        return $this->getMode()->is('filter');
    }
}