<?php

declare(strict_types=1);

namespace MonsieurBiz\SyliusSearchPlugin\Modifier;

use MonsieurBiz\SyliusSearchPlugin\Factory\GridConfig\GridConfigFactoryInterface;
use MonsieurBiz\SyliusSearchPlugin\Model\Config\GridConfigInterface;
use MonsieurBiz\SyliusSearchPlugin\Model\Document\FilterInterface;
use MonsieurBiz\SyliusSearchPlugin\Model\Document\FilterValueInterface;
use MonsieurBiz\SyliusSearchPlugin\Model\Document\ResultSetInterface;
use MonsieurBiz\SyliusSearchPlugin\Searcher\SearcherRegistryInterface;
use Symfony\Component\HttpFoundation\RequestStack;

class AggregatedFiltersModifier implements ResultSetModifierInterface
{
    public function __construct(
        private readonly SearcherRegistryInterface $searcherRegistry,
        private readonly GridConfigFactoryInterface $gridConfigFactory,
        private readonly RequestStack $requestStack,
    ) {
    }

    public function modify(
        GridConfigInterface $gridConfig,
        ResultSetInterface $resultSet,
    ): void {
        $overriddenGridConfig = $this->buildGridConfig($gridConfig);

        $resultSetWithFilters = $this->searcherRegistry->search($overriddenGridConfig);

        $this->removeImpossibleFilters($resultSetWithFilters, $resultSet, $gridConfig);
    }

    public function supports(GridConfigInterface $gridConfig, ResultSetInterface $resultSet): bool
    {
        return !$gridConfig->haveToApplyManuallyFilters();
    }

    private function getPossibleFilterValues(ResultSetInterface $resultSet): array
    {
        $values = [];
        foreach ($resultSet->getFilters() as $filter) {
            foreach ($filter->getValues() as $value) {
                $values[] = $this->getUniqueIdentifier($filter, $value);
            }
        }

        return $values;
    }

    private function getUniqueIdentifier(FilterInterface $filter, FilterValueInterface $value): string
    {
        return $filter->getCode() . '@' . $value->getSlug();
    }

    private function buildGridConfig(GridConfigInterface $originalGridConfig): GridConfigInterface
    {
        $gridConfigParameters = $originalGridConfig->getConfig();
        $gridConfigParameters['filters']['apply_manually'] = true;

        return $this->gridConfigFactory->create(
            $originalGridConfig->getType(),
            $this->requestStack->getMainRequest(),
            $originalGridConfig->getTaxon(),
            $gridConfigParameters,
        );
    }

    private function removeImpossibleFilters(
        ResultSetInterface $resultSetWithFilters,
        ResultSetInterface $resultSet,
        GridConfigInterface $originalGridConfig,
    ): void {
        $possibleValues = $this->getPossibleFilterValues($resultSetWithFilters);
        $filters = $resultSet->getFilters();
        $filtersToManage = [];
        foreach ($filters as $filter) {
            if (!array_key_exists($filter->getCode(), $originalGridConfig->getAppliedFilters())) {
                $filtersToManage[] = $filter;
            }
        }
        foreach ($filtersToManage as $filter) {
            foreach ($filter->getValues() as $value) {
                if (!\in_array($this->getUniqueIdentifier($filter, $value), $possibleValues, true)) {
                    $filter->removeValue($value);
                }
            }
        }
    }
}
