<?php

namespace KupShop\CatalogBundle\Util;

use KupShop\CatalogBundle\Enum\Ordering;
use KupShop\CatalogBundle\View\CategoryRequestHandler;
use KupShop\CatalogElasticBundle\View\SectionView;
use KupShop\IndexedFilterBundle\Util\FilterUrlParser;
use KupShop\KupShopBundle\Arrayable;
use KupShop\KupShopBundle\Exception\PermanentRedirectException;
use Psr\Log\LoggerInterface;
use Query\Operator;
use Symfony\Component\HttpFoundation\Request;

class CategoryResponse
{
    protected $categoryView;
    protected $campaignsUtil;
    protected $parser;

    /** @var SectionUtil */
    protected $sectionUtil;
    /** @var LoggerInterface */
    protected $logger;

    /** @var Request */
    protected $request;

    protected CategoryRequestHandler $view;

    /**
     * @return CategoryResponse
     *
     * @required
     */
    public function setCategoryView(CategoryRequestHandler $categoryView)
    {
        $this->categoryView = $categoryView;

        return $this;
    }

    /**
     * @return CategoryResponse
     *
     * @required
     */
    public function setCampaignsUtils(CampaignsUtil $campaignsUtil)
    {
        $this->campaignsUtil = $campaignsUtil;

        return $this;
    }

    /**
     * @return CategoryResponse
     *
     * @required
     */
    public function setParser(?FilterUrlParser $parser = null)
    {
        $this->parser = $parser;

        return $this;
    }

    /**
     * @required
     */
    public function setSectionUtil(SectionUtil $sectionUtil): void
    {
        $this->sectionUtil = $sectionUtil;
    }

    /**
     * @required
     */
    public function setLogger(LoggerInterface $logger): void
    {
        $this->logger = $logger;
    }

    public function getCategoryResponse(Request $request, ?CategoryRequestHandler $view = null)
    {
        return $this->getRequestedView($request, $view)->getResponse($request);
    }

    public function getRequestedView(Request $request, ?CategoryRequestHandler $view = null): CategoryRequestHandler
    {
        $this->setRequest($request)->setView($view);

        $this->setCategoryViewParameters();
        $this->findNextPrevProduct();

        return $this->view;
    }

    /**
     * @return $this
     */
    protected function setRequest(Request $request)
    {
        $this->request = $request;

        return $this;
    }

    /**
     * @return $this
     */
    protected function setView(?CategoryRequestHandler $view = null)
    {
        if (!$view) {
            $view = $this->categoryView;
        }
        $this->view = $view;

        if (method_exists($this->view, 'setRequest')) {
            $this->view->setRequest($this->request);
        }

        return $this;
    }

    protected function setCategoryViewParameters()
    {
        if ($this->request->attributes->get('campaign')) {
            $campaign = $this->request->attributes->get('campaign');
            $this->view->setCampaign($this->campaignsUtil->getCampaignByUrl($campaign));
        }

        if ($this->request->attributes->get('favourite')) {
            $this->view->setCampaign('F');
        }

        if ($this->request->attributes->get('id_producer')) {
            $id_producer = $this->request->attributes->get('id_producer');
            $this->view->setProducerId($id_producer);
        }

        if ($this->request->attributes->get('id_parameter_value')) {
            $id_parameter_value = $this->request->attributes->get('id_parameter_value');
            $id_parameter = sqlQueryBuilder()->select('id_parameter')->from('parameters_list')->where(Operator::equals(['id' => $id_parameter_value]))->execute()->fetchColumn();
            $this->view->setParameterValueId($id_parameter_value);
            $this->view->setParsedURLData(['parameters' => [$id_parameter => ['type' => \Filter::PARAM_LIST, 'value' => [$id_parameter_value]]]]);
        }

        if ($this->request->attributes->get('id_section')) {
            $id_section = $this->request->attributes->get('id_section');
            $parent_sections = $this->request->attributes->get('parent_sections');

            preg_match_all("#([-[:alnum:]]+)_k(\d+)/#", $parent_sections ?? '', $matches);

            $sections = $matches[2];
            array_push($sections, $id_section);

            $this->view->setCategoryId(end($sections));
        } else {
            $this->view->setCategoryId(0);
        }

        $parsedData = [];
        if ($this->request->attributes->get('parameters') && findModule(\Modules::INDEXED_FILTER)) {
            $parser = $this->parser;
            // Parse filter params from URL
            $parsedFilter = $parser->parseUrlParameters(urldecode($this->request->attributes->get('parameters')));
            $dynamicFilterConfiguration = $this->view->getDynamicFilterConfiguration();
            if ($dynamicFilterConfiguration instanceof Arrayable) {
                $dynamicFilterConfiguration = $dynamicFilterConfiguration->toArray();
            }

            $parsedData = $parser->getFilterParams($parsedFilter, $dynamicFilterConfiguration);
            // set parsed data to view
            $this->view->setParsedURLData($parsedData);
        }

        $filterData = $this->request->get('dynamic_filter', []);
        if (!is_array($filterData)) {
            $filterData = [];
            $this->request->query->remove('dynamic_filter');
            unset($_GET['dynamic_filter']);
        }
        if ($filterData) {
            $this->view->setFilterData($filterData);
        }

        if ($this->view instanceof SectionView) {
            if ($page = $this->request->query->get('page')) {
                $this->view->setPage((int) $page);
            }

            $order = $this->request->query->get('order', '');
            $ordering = Ordering::fromString($order);

            if ($ordering) {
                $this->view->setOrdering($ordering);
            }
        }
    }

    protected function findNextPrevProduct()
    {
        // Find next/prev product
        if ($nextProduct = intval($this->request->get('nextProduct'))) {
            $this->view->findNextPrevProduct($nextProduct);
        }
    }

    protected function checkCategoryUrl()
    {
        // check correct category url
        if ($urlCorrect = parse_url($this->view->getCorrectUrl(), PHP_URL_PATH)) {
            $urlCurrentOriginal = urldecode(parse_url($this->request->getRequestUri(), PHP_URL_PATH));
            $urlCurrent = $this->sectionUtil->removeFilterFromSectionUrl($this->request, $urlCurrentOriginal);

            if ($urlCurrent !== $urlCorrect) {
                if (strpos($urlCurrent, $urlCorrect) === 0) {
                    $this->logger->notice('Category: new redirect in checkCategoryUrl', [
                        'urlCorrect' => $urlCorrect,
                        'urlCurrent' => $urlCurrent,
                        'urlCurrentOriginal' => $urlCurrentOriginal,
                    ]);
                }

                $query = parse_url($this->request->getRequestUri(), PHP_URL_QUERY);
                if ($query) {
                    $query = '?'.$query;
                } else {
                    $query = null;
                }
                throw new PermanentRedirectException($urlCorrect.$query);
            }
        }
    }

    protected function getResponse(Request $request)
    {
        return $this->view->getResponse($request);
    }
}
