<?php

namespace KupShop\KupShopBundle\EventListener;

use KupShop\ContentBundle\View\ShopClosedView;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Context\DomainContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\KupShopBundle\Util\System\AsyncQueue;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\KernelEvents;

class RequestListener implements EventSubscriberInterface
{
    /**
     * @var EventDispatcherInterface
     */
    private $dispatcher;

    private $domains;
    /**
     * @var DomainContext
     */
    private $domainContext;

    protected AsyncQueue $queue;

    /** @required  */
    public function setQueue(AsyncQueue $queue)
    {
        $this->queue = $queue;
    }

    public function __construct(EventDispatcherInterface $dispatcher, DomainContext $domainContext)
    {
        $this->dispatcher = $dispatcher;
        $this->domainContext = $domainContext;
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::REQUEST => [
                ['checkShopClosed', 90],
                ['onKernelRequest', 100],
            ],
            KernelEvents::TERMINATE => [
                ['handleAsyncQueue', -10000],
            ],
        ];
    }

    public function handleAsyncQueue(TerminateEvent $event)
    {
        if (!isset($this->queue) || $this->queue->isEmpty()) {
            return;
        }

        // Finish current request, send response to client, process all remaining tasks
        if (function_exists('uwsgi_disconnect')) {
            uwsgi_disconnect();
        }

        $this->queue->handleAll();
    }

    public function checkShopClosed(RequestEvent $event)
    {
        $eventRequest = $event->getRequest();

        $dbcfg = \Settings::getDefault();
        $cfg = Config::get();
        if ($dbcfg->shop_closed == 'Y'
            && !(StringUtil::startsWith($eventRequest->getPathInfo().'/', "/{$cfg['Path']['admin']}")
                || StringUtil::startsWith($eventRequest->getPathInfo().'/', '/photo/'))
            && !getAdminUser()
        ) {
            $event->setResponse($this->shopClosed());
        }
    }

    public function onKernelRequest(RequestEvent $event)
    {
        // Když mám request z console, tak fakt nechci kontrolovat doménu a další věci
        if (!isFunctionalTests() && php_sapi_name() == 'cli') {
            return;
        }

        $eventRequest = $event->getRequest();

        // Dočasný hot-fix, když by někdo otravoval, tak ho zablokovat podle IP
        //        if (in_array($eventRequest->getClientIp(), ['178.34.150.202'])) {
        //            $event->setResponse(new \Symfony\Component\HttpFoundation\Response('', 403));
        //            return;
        //        }

        // Do not check for https and correct domain
        if ($eventRequest->attributes->has('ignore_checks')) {
            return;
        }

        // Never redirect on local development and review
        if ((isLocalDevelopment() || isBeta()) && !isFunctionalTests()) {
            return;
        }

        // https is missing so add it and redirect
        if ($eventRequest->getScheme() != 'https') {
            $event->setResponse(new RedirectResponse('https://'.$eventRequest->getHost().$eventRequest->getRequestUri(), 301));

            // Nedelam return, protoze mozna mam i spatnou domenu, tak at se to kdyztak redirectne najednou
        }

        // if urls are okay
        if (array_search($eventRequest->getHost(), $this->domainContext->getSupported()) !== false) {
            return;
        }

        // Save Blackfire monitoring budget - ignore redirects
        if (class_exists(\BlackfireProbe::class)) {
            //            \BlackfireProbe::ignoreTransaction();
        }

        // check if www is not missing
        $wwwHost = 'www.'.$eventRequest->getHost();
        if (array_search($wwwHost, $this->domains) !== false) {
            // www is missing so add it and redirect
            $url = 'https://'.$wwwHost.$eventRequest->getRequestUri();

            $event->setResponse(new RedirectResponse($url, 301));

            return;
        }

        // www check failed, so check for domain without www
        // remove www
        $host = preg_replace('/^www\./', '', $eventRequest->getHost());
        // check if domain without www exists in configuration
        if (in_array($host, $this->domains)) {
            $url = 'https://'.$host.$eventRequest->getRequestUri();

            $event->setResponse(new RedirectResponse($url, 301));

            return;
        }

        // fallback
        $url = "https://{$this->domainContext->getActiveId()}{$eventRequest->getRequestUri()}";
        $event->setResponse(new RedirectResponse($url, 301));
    }

    private function shopClosed()
    {
        // approved by Joe
        $view = ServiceContainer::getService(ShopClosedView::class);

        return $view->getResponse();
    }

    public function setDomains(array $domains)
    {
        $this->domains = $domains;
    }
}
