<?php

declare(strict_types=1);

namespace KupShop\CatalogElasticBundle\View;

use KupShop\CatalogBundle\CategorySort;
use KupShop\CatalogBundle\Entity\Producer;
use KupShop\CatalogBundle\Entity\Section;
use KupShop\CatalogBundle\Enum\Ordering;
use KupShop\CatalogBundle\ProductList\DynamicFilterAttributes;
use KupShop\CatalogBundle\Repository\ProducersRepository;
use KupShop\CatalogBundle\Repository\SectionsRepository;
use KupShop\CatalogBundle\Util\FilterUtil;
use KupShop\CatalogBundle\Util\IndexedFilterUtil;
use KupShop\CatalogBundle\Util\SectionUtil;
use KupShop\CatalogBundle\Util\SectionViewUtil;
use KupShop\CatalogBundle\View\CategoryRequestHandler;
use KupShop\ComponentsBundle\Twig\DataProvider\SectionDataProvider;
use KupShop\ComponentsBundle\View\ComponentsViewInterface;
use KupShop\ComponentsBundle\View\ComponentsViewTrait;
use KupShop\IndexedFilterBundle\Util\FilterUrlGenerator;
use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\KupShopBundle\Views\View;
use Query\Operator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class SectionView extends View implements CategoryRequestHandler, ComponentsViewInterface
{
    use ComponentsViewTrait;

    protected $template = 'view/section.html.twig';
    protected string $entrypoint = 'section';

    protected ?int $categoryId = null;
    protected ?int $producerId = null;
    protected ?int $parameterValueId = null;

    protected ?array $filterData = null;
    protected \FilterParams $filterParams;
    protected ?array $indexedFilterData = null;

    protected Ordering $ordering;
    protected int $page = 1;

    private Section $section; // use getSection() to get the section
    protected ?Producer $producer = null;
    protected array $indexed_filter;
    protected DynamicFilterAttributes $dynamicFilterAttributes;
    private array $breadcrumbs;

    public function __construct(
        protected readonly IndexedFilterUtil $indexedFilterUtil,
        protected readonly SectionViewUtil $categoryUtil,
        protected readonly SectionDataProvider $sectionDataProvider,
        protected readonly ProducersRepository $producersRepository,
        protected readonly SectionsRepository $sectionsRepository,
        protected readonly FilterUrlGenerator $filterUrlGenerator,
        protected readonly SectionUtil $sectionUtil,
    ) {
        $this->proxyCacheEnabled = findModule(\Modules::PROXY_CACHE, 'category');
    }

    public function getBodyVariables(): array
    {
        $body = parent::getBodyVariables();

        $body['id_category'] = $this->categoryId;
        $body['id_producer'] = $this->producerId;

        $body['baseFilterParams'] = $this->createBaseFilterParams();
        $body['filterParams'] = $this->filterParams = $this->createFilterParams();
        $body['indexedFilter'] = $this->getIndexedFilter($this->filterParams);

        $body['page'] = $this->page;
        $body['ordering'] = $this->getOrdering();

        $body['categorySort'] = match ($this->categoryId) {
            null => null,
            default => CategorySort::fromCategory($this->getSection(), $this->producerId),
        };

        $body['dynamicFilterConfiguration'] = $this->getDynamicFilterConfiguration();
        $body['fetchAllFilters'] = $this->getFetchAllFilters();

        return $body;
    }

    public function setProducerId($producerId)
    {
        $this->producerId = (int) $producerId;
        $this->producer = $this->producersRepository->getProducerEntity($this->producerId);

        if (!$this->producer) {
            throw new NotFoundHttpException("Producer {$producerId} not found!");
        }

        $this->sectionDataProvider->addProducer($this->producer);
    }

    public function setParameterValueId($parameterValueId)
    {
        $this->parameterValueId = $parameterValueId;
    }

    public function setCategoryId($categoryId)
    {
        $this->categoryId = (int) $categoryId;
    }

    protected function getSection()
    {
        if (isset($this->section)) {
            return $this->section;
        }
        // Fetch with parents - for breadcrumb navigation
        $section = $this->sectionsRepository->findById($this->categoryId);
        if (!$section) {
            throw new NotFoundHttpException("Section {$this->categoryId} not found");
        }

        $this->sectionDataProvider->addSection($section);

        return $this->section = $section;
    }

    public function getCorrectUrl(): ?string
    {
        if (!$this->categoryId && !$this->producerId) {
            return path('kupshop_catalog_catalog_category');
        }

        $path = [];

        if ($this->producerId) {
            $producerPath = path('kupshop_catalog_catalog_producer', [
                'id_producer' => $this->producerId,
                'url_producer' => StringUtil::slugify($this->producer->getName()),
            ]);
            $path[] = trim($producerPath, '/');
        }

        if ($this->categoryId > 0) {
            $section = $this->getSection();
            $sectionPath = ($this->producerId > 0 ? $section->getAutogeneratedUrl() : $section->getUrl());
            $path[] = trim($sectionPath, '/');
        }

        // (LegacyUrlGenerator) automaticky přidá locale prefix
        return path('page', ['path' => implode('/', $path).'/']);
    }

    protected function getCurrentUrl(Request $request): string
    {
        $currentUrl = parent::getCurrentUrl($request);

        return $this->sectionUtil->removeFilterFromSectionUrl($request, $currentUrl);
    }

    public function getBreadcrumbsNew(): array
    {
        if (isset($this->breadcrumbs)) {
            return $this->breadcrumbs;
        }

        $producer = $this->producer;
        $section = $this->getSection();

        $catProducer = $producer?->getId() ?? '';
        $catProducerTitle = $producer?->getName() ?? '';

        if ($section->getId() > 0) {
            $breadcrumbs = [];

            foreach ($section->getParents() as $parent) {
                if ($parent->getId() === $section->getId()) {
                    // add active section
                    $breadcrumbs[] = [
                        'text' => $section->getNameShort() ?: $section->getName(),
                        'ID' => $parent->getId(),
                        'link' => path('page', ['path' => $section->getUrl()]),
                    ];

                    continue;
                }

                $breadcrumbs[] = [
                    'text' => $parent->getNameShort() ?: $parent->getName(),
                    'link' => path('page', ['path' => $parent->getUrl()]),
                    'ID' => $parent->getId(),
                ];
            }

            if (!empty($catProducerTitle)) {
                $home = sprintf(translate('getSections', 'functions')['catalogProducer'], $catProducerTitle);

                array_unshift($breadcrumbs, [
                    'text' => $home,
                    'link' => createScriptURL([
                        'URL' => 'launch.php',
                        's' => 'category',
                        'IDpd' => $catProducer,
                        'producerTitle' => $catProducerTitle,
                        'TITLE' => $home,
                    ]),
                    'ID' => '0',
                ]);
            }

            array_unshift($breadcrumbs, [
                'text' => translate('getSections', 'functions')['home'],
                'link' => createScriptURL([
                    'URL' => 'launch.php',
                    's' => 'index',
                ]),
            ]);

            return $this->breadcrumbs = $breadcrumbs;
        }

        $breadcrumbs = [];
        if ($catProducer) {
            $home = sprintf(translate('getSections', 'functions')['catalogProducer'], $catProducerTitle);
        } else {
            $home = translate('getSections', 'functions')['catalog'];
        }

        if (!empty($home)) {
            array_unshift($breadcrumbs, [
                'text' => $home,
            ]);
        }

        array_unshift($breadcrumbs, [
            'text' => translate('getSections', 'functions')['home'],
            'link' => createScriptURL([
                'URL' => 'launch.php',
                's' => 'index',
            ]),
        ]);

        return $breadcrumbs;
    }

    public function getWpjToolbar()
    {
        $wpjToolbar = [];

        if ($this->categoryId > 0) {
            $params = ['ID' => $this->categoryId];
            if ($this->producerId > 0) {
                $params['id_producer'] = $this->producerId;
            }
            $wpjToolbar = [
                'url' => getAdminUrl('sections', $params),
                'title' => 'Upravit sekci',
                'translateUrl' => getAdminUrl('list', [
                    'type' => 'translateSections',
                    'iframe' => 1,
                    'objectIDs' => $this->categoryId,
                ]),
                'translateTitle' => 'Překlad sekce',
            ];
        } elseif ($this->producerId > 0) {
            $wpjToolbar = [
                'url' => getAdminUrl('producers', ['ID' => $this->producerId]),
                'title' => 'Upravit výrobce',
                'translateUrl' => getAdminUrl('list', [
                    'type' => 'translateProducers',
                    'iframe' => 1,
                    'objectIDs' => $this->producerId,
                ]),
                'translateTitle' => 'Překlad výrobce',
            ];
        }
        $wpjToolbar['indexed_filter'] = $this->getIndexedFilterAdminUrl();

        return array_merge(parent::getWpjToolbar(), $wpjToolbar);
    }

    public function getIndexedFilterAdminUrl()
    {
        $url = false;
        if ($indexed_filter = $this->indexed_filter ?? null) {
            if (!empty($indexed_filter['id'])) {
                $params = ['ID' => $indexed_filter['id']];
            } else {
                $params = $indexed_filter + ['title' => $this->getTitle()];
            }
            $url = getAdminUrl('IndexedFiltersContent', $params);
        }

        return $url;
    }

    protected function getIndexedFilter(\FilterParams $filterParams)
    {
        if (!isset($this->indexed_filter)) {
            $this->indexed_filter = $this->indexedFilterUtil->getIndexedFilter(
                $this->categoryId,
                $this->producerId,
                $filterParams,
            ) ?: [];
        }

        return $this->indexed_filter;
    }

    public function getMetaTitle()
    {
        if (!empty($this->indexed_filter['meta_title'])) {
            return $this->indexed_filter['meta_title'];
        }

        return $this->categoryUtil->createTitle(
            $this->getSection(),
            $this->producer,
            $this->createFilterParams(),
            $this->getDynamicFilterConfiguration(),
        );
    }

    public function getTitle(): string
    {
        return $this->getMetaTitle();
    }

    public function getMetaDescription(): string
    {
        if (!empty($this->indexed_filter['meta_description'])) {
            return $this->indexed_filter['meta_description'];
        }

        return $this->categoryUtil->createMetaDescription($this->getSection(), $this->producer);
    }

    public function createFilterParams(): \FilterParams
    {
        $filterParams = $this->createBaseFilterParams();

        $filterData = FilterUtil::mergeIndexedAndDynamicFilterData(
            $this->getDynamicFilterConfiguration(),
            $this->filterData ?? [],
            $this->indexedFilterData ?? [],
        );

        if (!empty($filterData)) {
            $filter = new \Filter($filterParams);
            $filter->setFilterData($filterData);
        }

        return $filterParams;
    }

    private function createBaseFilterParams(): \FilterParams
    {
        $filterParams = \FilterParams::createDefault();

        if ($this->categoryId !== null) {
            if ($this->categoryId === -1) {
                $filterParams->setSearch($this->filterData['search'] ?? '');
            }

            if ($this->categoryId === 0 || $this->getSection()->displayProductsFromSubsections()) {
                $filterParams->setSectionsFilter([$this->categoryId]);
            } else {
                $filterParams->setSections([$this->categoryId]);
            }
        }

        if ($this->producerId) {
            $filterParams->setProducers([$this->producerId]);
        }

        if ($this->parameterValueId) {
            $parameterId = sqlQueryBuilder()
                ->select('id_parameter')
                ->from('parameters_list')
                ->andWhere(Operator::equals(['id' => $this->parameterValueId]))
                ->execute()
                ->fetchOne();

            $filterParams->setParameter($parameterId, [$this->parameterValueId]);
        }

        return $filterParams;
    }

    private function getOrdering(): ?Ordering
    {
        if (!isset($this->ordering)) {
            if (isset($this->categoryId)) {
                return null;
            }

            if ($this->producer?->getOrderby()) {
                return $this->ordering = new Ordering($this->producer->getOrderby(), $this->producer->getOrderdir());
            }
        }

        return $this->ordering;
    }

    public function setOrdering(Ordering $ordering): void
    {
        $this->ordering = $ordering;
    }

    public function setPage(int $page): void
    {
        $this->page = $page;
    }

    public function setFilterData(array $filterData): self
    {
        $this->filterData = $filterData;

        return $this;
    }

    public function setParsedURLData($indexedFilterData)
    {
        $this->indexedFilterData = $indexedFilterData;
    }

    public function getDynamicFilterConfiguration(): DynamicFilterAttributes
    {
        return $this->dynamicFilterAttributes ??= $this->categoryUtil->getDynamicFilterConfiguration($this->getSection(), $this->producerId);
    }

    protected function getFetchAllFilters(): bool
    {
        $allFilters = FilterUtil::mergeIndexedAndDynamicFilterData(
            $this->getDynamicFilterConfiguration(),
            $this->filterData ?? [],
            $this->indexedFilterData ?? [],
        );

        return !empty($allFilters);
    }

    public function setCampaign($campaign)
    {
        throw new NotFoundHttpException('Campaigns not supported!');
    }

    public function getCanonicalUrl(Request $request)
    {
        if ($this->producerId) {
            $this->filterUrlGenerator->setIgnoreProducer(true);
        }

        if ($this->categoryId <= 0) {
            $path = $request->getPathInfo();
        } else {
            $this->filterUrlGenerator->setSectionId($this->categoryId);
            $this->filterUrlGenerator->setFilterParams($this->filterParams);
            $this->filterUrlGenerator->setCategoryUrl($this->getCorrectUrl());

            $indexedUrl = $this->filterUrlGenerator->generateIndexedUrl();

            $path = $request->getSchemeAndHttpHost().$indexedUrl['url'];
        }

        // Hack? Maybe no ...
        if (!$this->filterData && $page = $request->query->get('page')) {
            $page = intval($page);
            if ($page > 1) {
                $path .= '?page='.$page;
            }
        }

        return $path;
    }

    public function getCategoryId(): ?int
    {
        return $this->categoryId;
    }

    public function getProducerId(): ?int
    {
        return $this->producerId;
    }

    public function getTemplate(): string
    {
        return $this->getSection()->getTemplate() ?: $this->template;
    }

    public function getTemplates(): iterable
    {
        // List all shop templates in section
        if (is_dir(__DIR__.'/../../../../../shop/twig/view/section')) {
            foreach (new \FilesystemIterator(__DIR__.'/../../../../../shop/twig/view/section') as $file) {
                yield 'view/section/'.$file->getFilename();
            }
        }

        yield from [
            $this->template,
            'view/search.html.twig',
            'block.productList.html.twig',
        ];
    }
}
