<?php

namespace KupShop\ComponentsBundle\Twig\Components\Section;

use Elastica\Multi\Search as MultiSearch;
use KupShop\CatalogBundle\Entity\Section;
use KupShop\CatalogBundle\ProductList\Builder\CompileStrategy;
use KupShop\CatalogBundle\ProductList\Builder\FilteredProductListBuilder;
use KupShop\CatalogBundle\Repository\SectionsRepository;
use KupShop\CatalogElasticBundle\Elastica\QueryBuilder;
use KupShop\CatalogElasticBundle\Util\ElasticQueryClient;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\ComponentsBundle\Twig\DataProvider\SectionDataTrait;
use KupShop\KupShopBundle\Context\CacheContext;
use KupShop\KupShopBundle\Util\StringUtil;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent(template: '@Components/components/Section/SectionTree/SectionTree.1.html.twig')]
#[Component(1, [
    new Version(1),
])]
class SectionTree extends BaseComponent
{
    use SectionDataTrait;

    use QueryBuilder;

    public bool $singleRootTree = false;

    public bool $allSectionsLink = false;

    public bool $sectionsModalOpener = false;

    public ?array $filterIds = null;

    public string $iconShow = 'plus';

    public string $iconHide = 'close';

    public int $level = 0;

    public int $levelMax = 7;

    /** @var array Section[] */
    protected array $sections;

    public function __construct(
        private readonly \KupShop\CatalogBundle\Section\SectionTree $sectionTree,
        private readonly CacheContext $cacheContext,
        private readonly CompileStrategy $strategy,
        private readonly SectionsRepository $sectionsRepository,
    ) {
    }

    /**
     * @return Section[]
     */
    public function getSections(): array
    {
        if (!isset($this->sections)) {
            $this->sections = $this->sectionTree->getTree();
            unset($this->sections[-1]); // search section with ID=-1 (sekce Vyhledávání)
        }

        if ($this->id_producer && $this->filterIds == null) {
            $this->filterIds = $this->getProducerSectionIds($this->id_producer);
        }

        if ($this->singleRootTree) {
            $openedTree = $this->getSelection();

            return [$this->sectionTree->getSectionById(reset($openedTree))];
        }

        return $this->sections;
    }

    protected function getProducerSectionIds(int $idProducer)
    {
        $filterParams = \FilterParams::createDefault();
        $filterParams->setProducers([$idProducer]);

        $result = (new FilteredProductListBuilder())
               ->baseFilterParams($filterParams)->build($this->strategy);

        $result->onBeforeExecute(function (MultiSearch $multiSearch) {
            $multiSearch->getSearches()[ElasticQueryClient::$mainQueryName]
                ->getQuery()
                ->setSize(0)
                ->addAggregation($this->agg()->terms('producer_sections')->setField('filter_section_recursive')->setSize(10000));
        });

        $aggregations = $result->getResponse()[ElasticQueryClient::$mainQueryName]->getAggregation('producer_sections');

        return array_reduce($aggregations['buckets'] ?? [], function ($result, $value) {
            $result[] = $value['key'];

            return $result;
        }, [0]);
    }

    public function getSelection(): array
    {
        return array_keys($this->section['parents'] ?? []);
    }

    public function getCacheKey(): string
    {
        $updated = sqlQueryBuilder()->select('UNIX_TIMESTAMP(MAX(date_updated))')->from('sections')->execute()->fetchOne();

        $key = StringUtil::slugify($this->cacheContext->getKey(['text']).'_'.static::class.'_'.($this->id_producer ?? '').'_'.$updated);

        if ($this->singleRootTree) {
            $openedTree = $this->getSelection();

            $key .= '_'.reset($openedTree);
        }

        return $key;
    }

    public function getHasSections(): bool
    {
        foreach ($this->getSections() as $section) {
            if (!$section->getChildren()->isEmpty()) {
                return true;
            }
        }

        return false;
    }

    public function getName(Section $section): string
    {
        return $section->getNameShort() ?: $section->getName();
    }
}
