<?php 
 
namespace Slivki\EventSubscriber; 
 
use Doctrine\ORM\EntityManagerInterface; 
use Slivki\Controller\SiteController; 
use Slivki\Entity\MailingCampaign; 
use Slivki\Entity\MailingStatistic; 
use Slivki\Entity\Seo; 
use Slivki\Entity\User; 
use Slivki\Enum\Order\Domain; 
use Slivki\Services\City\CityCacheService; 
use Slivki\Services\City\CityProvider; 
use Slivki\Services\MailingCampaign\Partner\PartnerMailingCampaignClickHandler; 
use Slivki\Util\CommonUtil; 
use Slivki\Entity\City; 
use Slivki\Util\Iiko\BurgerKing; 
use Slivki\Util\Iiko\Crabs; 
use Slivki\Util\Iiko\DinnerBuffet; 
use Slivki\Util\Iiko\Dodo; 
use Slivki\Util\Iiko\Dominos; 
use Slivki\Util\Iiko\PirogiBy; 
use Slivki\Util\Iiko\Pirogovaya1; 
use Slivki\Util\Iiko\Shtolle; 
use Slivki\Util\Iiko\SushiChefArts; 
use Slivki\Util\Iiko\SushiVesla; 
use Slivki\Util\Iiko\Urbanfood; 
use Slivki\Util\Iiko\WokiToki; 
use Slivki\Util\SoftCache; 
use Symfony\Component\EventDispatcher\EventSubscriberInterface; 
use Symfony\Component\HttpFoundation\Cookie; 
use Symfony\Component\HttpFoundation\RedirectResponse; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\HttpKernel\Event\RequestEvent; 
use Symfony\Component\HttpKernel\Event\ResponseEvent; 
use Symfony\Component\HttpKernel\KernelEvents; 
 
final class KernelControllerSubscriber implements EventSubscriberInterface 
{ 
    private const PATTERNS_FOR_NOT_REDIRECT = [ 
        'delivery', 
        'gift-certificate', 
        'login', 
        'api/online-order/', 
    ]; 
 
    private array $allowedSubdomains = [ 
        'tokiny', 
        'sushihouse', 
        'm', 
        'marketplace', 
        'okpirog', 
        SushiChefArts::DOMAIN, 
        'citysushi', 
        'tuna', 
        'fsushi', 
        'moresushi', 
        '73', 
        WokiToki::DOMAIN, 
        DinnerBuffet::DOMAIN, 
        Dominos::DOMAIN, 
        'sushi-master', 
        'mp', 
        PirogiBy::DOMAIN, 
        Pirogovaya1::DOMAIN, 
        BurgerKing::DOMAIN, 
        Crabs::DOMAIN, 
        'deka', 
        Shtolle::DOMAIN, 
        Dodo::DOMAIN, 
        'whitelotus', 
        'marsel', 
        'shah', 
        'avokado', 
        'express-pizza', 
        'heropark', 
        'thesushi', 
        SushiVesla::DOMAIN, 
        Urbanfood::DOMAIN, 
        'profisushi', 
        'artsushi', 
        'byrolls', 
        'ajia', 
        'jasmin', 
        'ustrica', 
        'pastadeli', 
        Domain::OUSHEN, 
        'sea', 
        'wineseafood', 
        'izumi', 
        'delyga', 
        'zhanchay', 
        'sushimaster', 
        Domain::TOKIO_SUSHI, 
        Domain::MEGASUN, 
        'lotosart', 
    ]; 
 
    private array $placeHolderDomains = []; 
 
    private $baseDomain; 
    private EntityManagerInterface $entityManager; 
    private CityCacheService $cityCacheService; 
    private PartnerMailingCampaignClickHandler $partnerMailingCampaignClickHandler; 
    private CityProvider $cityProvider; 
 
    public function __construct( 
        EntityManagerInterface $entityManager, 
        CityCacheService $cityCacheService, 
        PartnerMailingCampaignClickHandler $partnerMailingCampaignClickHandler, 
        CityProvider $cityProvider, 
        string $baseDomain 
    ) { 
        $this->baseDomain = $baseDomain; 
        $this->entityManager = $entityManager; 
        $this->cityCacheService = $cityCacheService; 
        $this->partnerMailingCampaignClickHandler = $partnerMailingCampaignClickHandler; 
        $this->cityProvider = $cityProvider; 
    } 
 
    public static function getSubscribedEvents(): array 
    { 
        return [ 
            KernelEvents::REQUEST => ['onKernelRequest', 33], 
            KernelEvents::RESPONSE => ['onKernelResponse', 33] 
        ]; 
    } 
 
    public function onKernelRequest(RequestEvent $event): void 
    { 
        if (!$event->isMainRequest()) { 
            return; 
        } 
 
        $request = $event->getRequest(); 
        $pathInfo = $request->getPathInfo(); 
        $hostExploded = explode('.', $request->getHost()); 
        $subDomain = $hostExploded[0]; 
        if ($subDomain === 'delyga') { 
            return; 
        } 
 
        if (\in_array($subDomain, $this->allowedSubdomains, true) && !$this->isIncludedToRoute($pathInfo)) { 
            $event->setResponse(new RedirectResponse( 
                \sprintf( 
                    'https://%s%s%s', 
                    $request->getSession()->get(City::CITY_DOMAIN_SESSION_KEY, 'www'), 
                    $this->baseDomain, 
                    $pathInfo, 
                ), 
                Response::HTTP_TEMPORARY_REDIRECT, 
            )); 
 
            return; 
        } 
 
        $cityID = $this->cityProvider->getDefaultCityId(); 
        $request->getSession()->set(City::CITY_ID_SESSION_KEY, $cityID); 
 
        if (!in_array($subDomain, $this->allowedSubdomains, true)) { 
            if ('' !== $subDomain && 'www' !== $subDomain) { 
                $subDomainCityId = $this->cityCacheService->getCityIdByDomain($subDomain); 
                if (null === $subDomainCityId) { 
                    $event->setResponse(new RedirectResponse($this->baseDomain . $pathInfo, 302)); 
                } else { 
                    $cityID = $subDomainCityId; 
                } 
            } 
            $request->getSession()->set(City::CITY_ID_SESSION_KEY, $cityID); 
            $request->getSession()->set(City::CITY_DOMAIN_SESSION_KEY, $subDomain); 
            if (City::DEFAULT_CITY_ID === $cityID && 'www' !== $subDomain) { 
                $event->setResponse(new RedirectResponse('https://www' . $this->baseDomain, 301)); 
                return; 
            } 
        } 
 
        $this->saveMailingStatistic($request); 
        $this->partnerMailingCampaignClickHandler->handle($request); 
        $seoRepository = $this->entityManager->getRepository(Seo::class); 
        $metaInfo = $seoRepository->getByAlias($pathInfo, $subDomain, $this->baseDomain); 
        if (isset($this->placeHolderDomains[$subDomain])) { 
            $request->attributes->set('_controller', "Slivki\\Controller\\DefaultController::domainPlaceHolderAction"); 
            $request->attributes->set("entityID", $this->placeHolderDomains[$subDomain]); 
            return; 
        } 
        if ($metaInfo && $metaInfo != SoftCache::EMPTY_VALUE) { 
            $exploded = explode(':', $metaInfo->getResourceURL()); 
            $url = "Slivki\\Controller\\" . $exploded[1] . "Controller::" . $exploded[2] . 'Action'; 
            $request->attributes->set('_controller', $url); 
            $request->attributes->set("entityID", $metaInfo->getEntityID()); 
            $request->attributes->set(SiteController::PARAMETER_META_INFO, $metaInfo); 
            if (!$metaInfo->isActive() && !in_array($subDomain, $this->allowedSubdomains)) { 
                $redirectURL = $metaInfo->getRedirectURL();; 
                if ($request->query->count()) { 
                    $parameters = []; 
                    foreach ($request->query->all() as $key => $value) { 
                        $parameters[] = $key . '=' . $value; 
                    } 
                    $redirectURL .= '?' . implode('&', $parameters); 
                } 
                $event->setResponse(new RedirectResponse($redirectURL, 301)); 
            } 
        } 
    } 
 
    public function onKernelResponse(ResponseEvent $event) { 
        $refID = $event->getRequest()->query->get('ref'); 
        if ($refID) { 
            $cookie = Cookie::create('refID', $refID, new \DateTime('+1 month')); 
            $event->getResponse()->headers->setCookie($cookie); 
        } 
    } 
 
    private function saveMailingStatistic(Request $request) { 
        $query = $request->query; 
        $mailingCampaignID = $query->getInt('utm_campaign'); 
        $userID = $query->getInt('utm_b'); 
        $entityID = $query->getInt('utm_c'); 
        $entityType = $query->getInt('utm_d'); 
        $entityManager = $this->entityManager; 
 
        // Рассылка с бонусом для Могилева 
        if ($mailingCampaignID == 1041 && $userID) { 
            $user = $entityManager->find(User::class, $userID); 
            if (!$user) { 
                return; 
            } 
            if ($entityManager->getRepository(User::class)->setMogilevMailingBonus($user)) { 
                $request->getSession()->getFlashBag()->add('showMogilevMailingBonusPopup', '1'); 
            } 
            return; 
        } 
 
        // Рассылка с бонусом для Гомеля 
        if ($mailingCampaignID == 1042 && $userID) { 
            $user = $entityManager->find(User::class, $userID); 
            if (!$user) { 
                return; 
            } 
            if ($entityManager->getRepository(User::class)->setGomelMailingBonus($user)) { 
                $request->getSession()->getFlashBag()->add('showMogilevMailingBonusPopup', '1'); 
            } 
            return; 
        } 
 
        if (!$mailingCampaignID || !$entityType || !$entityID) { 
            return; 
        } 
        $mailingCampaign = $entityManager->find(MailingCampaign::class, $mailingCampaignID); 
        if (!$mailingCampaign) { 
            return; 
        } 
        $mailingStatistic = new MailingStatistic(); 
        $mailingStatistic->setMobileVersion(CommonUtil::isMobileDevice($request)); 
        $user = null; 
        if ($userID) { 
            $user = $entityManager->find(User::class, $userID); 
            if ($user) { 
                $mailingStatistic->setUser($user); 
            } 
        } 
        $mailingStatistic->setIpAddress($request->getClientIp()); 
        $mailingStatistic->setMailingCampaign($mailingCampaign); 
        $mailingStatistic->setEntityID($entityID); 
        $mailingStatistic->setEntityType($entityType); 
        $entityManager->persist($mailingStatistic); 
        $entityManager->flush(); 
    } 
 
    private function isIncludedToRoute(string $pathInfo): bool 
    { 
        $matches = \array_filter( 
            self::PATTERNS_FOR_NOT_REDIRECT, 
            static fn(string $needle): bool => false !== strpos($pathInfo, $needle), 
        ); 
 
        return 0 < \count($matches); 
    } 
}