<?php

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\EventListener;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Client\IpGeoClient;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Utils\Mailer;
use CpCreation\VitiCore\Shop\Model\ShopConfig;
use CpCreation\VitiCore\Shop\Repository\ShopConfigDisableCountryRepository;
use CpCreation\VitiCore\Shop\Repository\ShopConfigRepository;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;

#[AsEventListener(event: KernelEvents::REQUEST, method: 'onKernelRequest', priority: 9)]
final class FilterShopCountrySubscriber
{
    public function __construct(
        private readonly IpGeoClient $ipGeoClient,
        private readonly ShopConfigRepository $shopConfigRepository,
        private readonly ShopConfigDisableCountryRepository $shopConfigDisableCountryRepository,
        private readonly RequestStack $requestStack,
        private readonly Mailer $mailer,
        private readonly string $ipGeoAccessKey,
        private readonly string $kernelEnvironment,
        private readonly string $ipGeoTestCountry,
    ) {}

    private function getSession(): ?SessionInterface
    {
        return $this->requestStack->getSession();
    }

    public function onKernelRequest(RequestEvent $event): void
    {
        if (!$event->isMainRequest()) {
            return;
        }

        $request = $event->getRequest();

        if ('shop' !== $request->attributes->get('_route')) {
            return;
        }

        $userAgent = (string) $request->headers->get('User-Agent', '');

        if (preg_match('/baidu|dareboost|bingbot|facebookexternalhit|googlebot|-google|ia_archiver|msnbot|naverbot|pingdom|seznambot|slurp|teoma|twitter|yandex|yeti|speed|insights|woobot|ighth|tmetr|eadle|gtmetrix|lighthouse/i', $userAgent)) {
            $this->getSession()?->set('country', 'FR');
            $this->getSession()?->set('blockShop', false);

            return;
        }

        $forcedCountry = 'dev' === $this->kernelEnvironment
            ? strtoupper(trim($this->ipGeoTestCountry))
            : '';

        if ('' !== $forcedCountry) {
            $this->getSession()?->set('country', $forcedCountry);
            $this->testCountry($forcedCountry);

            return;
        }

        $blockShop = $this->getSession()?->get('blockShop', null);
        if (null !== $blockShop) {
            return;
        }

        $country = 'FR';

        try {
            $response = $this->ipGeoClient->get(
                '/' . $request->getClientIp(),
                [
                    'query' => [
                        'access_key' => $this->ipGeoAccessKey,
                    ],
                ]
            );

            $result = json_decode($response->getBody()->getContents(), true);

            if (!empty($result['country_code'])) {
                $country = (string) $result['country_code'];
            } else {
                $this->mailer->sendErrorIpLocate(
                    'Request OK, but country is not defined ' . json_encode($result),
                    (string) $request->getClientIp()
                );
            }
        } catch (\Throwable $e) {
            $this->mailer->sendErrorIpLocate($e->getMessage(), (string) $request->getClientIp());
        }

        $this->testCountry($country);
    }

    /**
     * @throws \Doctrine\ORM\NonUniqueResultException
     */
    private function testCountry(string $country): void
    {
        $configShop = $this->shopConfigRepository->findOne();

        if (!$configShop instanceof ShopConfig) {
            $this->getSession()?->set('blockShopCountry', $country);
            $this->getSession()?->set('blockShop', false);

            return;
        }

        if ($configShop->getDisableCountries()->count() > 0) {
            if ($this->shopConfigDisableCountryRepository->findOneBy(['country' => $country])) {
                $this->getSession()?->set('blockShop', true);
                $this->getSession()?->set('blockShopCountry', $country);

                return;
            }
        }

        if (\count($configShop->getEnableCountriesForShop()) > 0) {
            if (!\in_array($country, $configShop->getEnableCountriesForShop(), true)) {
                $this->getSession()?->set('blockShop', true);
                $this->getSession()?->set('blockShopCountry', $country);

                return;
            }
        }

        $this->getSession()?->set('blockShopCountry', $country);
        $this->getSession()?->set('blockShop', false);
    }
}
