<?php

declare(strict_types=1);

namespace MonsieurBiz\SyliusSearchPlugin\Controller;

use MonsieurBiz\SyliusSearchPlugin\Context\TaxonContextInterface;
use MonsieurBiz\SyliusSearchPlugin\Exception\MissingLocaleException;
use MonsieurBiz\SyliusSearchPlugin\Exception\NotSupportedTypeException;
use MonsieurBiz\SyliusSearchPlugin\Factory\GridConfig\GridConfigFactoryInterface;
use MonsieurBiz\SyliusSearchPlugin\Helper\RenderDocumentUrlHelperInterface;
use MonsieurBiz\SyliusSearchPlugin\Model\Config\GridConfigInterface;
use MonsieurBiz\SyliusSearchPlugin\Model\Document\Result;
use MonsieurBiz\SyliusSearchPlugin\Modifier\CompositeResultSetModifierInterface;
use MonsieurBiz\SyliusSearchPlugin\Searcher\SearcherRegistryInterface;
use NumberFormatter;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Currency\Context\CurrencyContextInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;

class SearchController extends AbstractController
{
    public const SORT_ASC = 'asc';

    public const SORT_DESC = 'desc';

    public function __construct(
        private readonly Environment $templatingEngine,
        private readonly ChannelContextInterface $channelContext,
        private readonly CurrencyContextInterface $currencyContext,
        private readonly TaxonContextInterface $taxonContext,
        private readonly GridConfigFactoryInterface $gridConfigFactory,
        private readonly RenderDocumentUrlHelperInterface $renderDocumentUrlHelper,
        private readonly SearcherRegistryInterface $searcherRegistry,
        private readonly CompositeResultSetModifierInterface $resultSetModifierRegistry,
    ) {
    }

    public function postAction(Request $request): RedirectResponse
    {
        $query = $request->request->all('monsieurbiz_searchplugin_search')['query'] ?? '';

        return new RedirectResponse(
            $this->generateUrl(
                'monsieurbiz_sylius_search_search',
                ['query' => urlencode($query)],
            ),
        );
    }

    /**
     * Perform the search action & display results. User can add page, limit or sorting.
     */
    public function searchAction(Request $request): Response
    {
        $gridConfig = $this->gridConfigFactory->create(
            GridConfigInterface::SEARCH_TYPE,
            $request,
        );

        $resultSet = $this->searcherRegistry->search($gridConfig);
        $this->resultSetModifierRegistry->modify($gridConfig, $resultSet);

        // Redirect to document if only one result and no filter applied
        $appliedFilters = $gridConfig->getAppliedFilters();
        if (1 === $resultSet->getTotalHits() && count($appliedFilters) === 0) {
            /** @var Result $document */
            $document = current($resultSet->getResults());

            try {
                $urlParams = $this->renderDocumentUrlHelper->getUrlParams($document);

                return new RedirectResponse($this->generateUrl($urlParams->getPath(), $urlParams->getParams()));
            } catch (NotSupportedTypeException) {
                // Return list of results if cannot redirect, so ignore Exception
            } catch (MissingLocaleException) {
                // Return list of results if locale is missing
            }
        }

        // Get number formatter for currency
        $currencyCode = $this->currencyContext->getCurrencyCode();
        $formatter = new NumberFormatter($request->getLocale() . '@currency=' . $currencyCode, NumberFormatter::CURRENCY);

        // Display result list
        return new Response($this->templatingEngine->render('@MonsieurBizSyliusSearchPlugin/Search/result.html.twig', [
            'query' => $gridConfig->getQuery(),
            'limits' => $gridConfig->getLimits(),
            'resultSet' => $resultSet,
            'channel' => $this->channelContext->getChannel(),
            'currencyCode' => $this->currencyContext->getCurrencyCode(),
            'moneySymbol' => $formatter->getSymbol(NumberFormatter::CURRENCY_SYMBOL),
            'gridConfig' => $gridConfig,
        ]));
    }

    /**
     * Perform the instant search action & display results.
     */
    public function instantAction(Request $request): Response
    {
        $gridConfig = $this->gridConfigFactory->create(
            GridConfigInterface::INSTANT_TYPE,
            $request,
        );

        $resultSet = $this->searcherRegistry->search($gridConfig);
        $this->resultSetModifierRegistry->modify($gridConfig, $resultSet);

        // Display instant result list
        return new Response($this->templatingEngine->render('@MonsieurBizSyliusSearchPlugin/Instant/result.html.twig', [
            'query' => $gridConfig->getQuery(),
            'resultSet' => $resultSet,
            'channel' => $this->channelContext->getChannel(),
            'currencyCode' => $this->currencyContext->getCurrencyCode(),
            'gridConfig' => $gridConfig,
        ]));
    }

    /**
     * Perform the taxon action & display results.
     */
    public function taxonAction(Request $request): Response
    {
        $gridConfig = $this->gridConfigFactory->create(
            GridConfigInterface::TAXON_TYPE,
            $request,
            $this->taxonContext->getTaxon(),
        );

        $resultSet = $this->searcherRegistry->search($gridConfig);
        $this->resultSetModifierRegistry->modify($gridConfig, $resultSet);

        // Get number formatter for currency
        $currencyCode = $this->currencyContext->getCurrencyCode();
        $formatter = new NumberFormatter($request->getLocale() . '@currency=' . $currencyCode, NumberFormatter::CURRENCY);

        // Display result list
        return new Response($this->templatingEngine->render('@MonsieurBizSyliusSearchPlugin/Taxon/result.html.twig', [
            'taxon' => $gridConfig->getTaxon(),
            'limits' => $gridConfig->getLimits(),
            'resultSet' => $resultSet,
            'channel' => $this->channelContext->getChannel(),
            'currencyCode' => $this->currencyContext->getCurrencyCode(),
            'moneySymbol' => $formatter->getSymbol(NumberFormatter::CURRENCY_SYMBOL),
            'gridConfig' => $gridConfig,
        ]));
    }
}
