<?php

namespace App\Security;

use App\Service\DiscordWebhookService;
use App\Service\Mailer\Mailer;
use App\Service\Signature\Client;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
use Twig\Environment;

#[AsEventListener(RequestEvent::class, method: 'onLocked', priority: 10)]
#[AsEventListener(RequestEvent::class, method: 'onControl', priority: 5)]
class IntranetLocked
{
    private const WHITELISTED_IPS = [
        '212.114.31.239', // Bureau
        '1.2.3.4',        // Autre
        '172.19.0.1',
    ];

    public function __construct(
        private readonly Environment $environment,
        private readonly Client $signatureClient,
        private readonly \App\Service\Search\Client $searchClient,
        private readonly \App\Service\Stripe\Client $stripeClient,
        private readonly Mailer $mailer,
        private readonly CacheInterface $cache, // Injection du cache
        private readonly DiscordWebhookService $discordWebhookService
    ) {}

    public function onLocked(RequestEvent $requestEvent): void
    {
        if ($this->isWhitelisted($requestEvent) || $this->isDebugRoute($requestEvent)) {
            return;
        }

        if (($_ENV['INTRANET_LOCK'] ?? 'false') === 'true') {
            $response = new Response($this->environment->render('security/locked.twig'));
            $response->setStatusCode(Response::HTTP_FORBIDDEN);
            $requestEvent->setResponse($response);
        }
    }

    public function onControl(RequestEvent $requestEvent): void
    {
        if ($this->isWhitelisted($requestEvent) || $this->isDebugRoute($requestEvent)) {
            return;
        }

        // On récupère le statut depuis le cache (Clé : intranet_status)
        $status = $this->cache->get('intranet_services_status', function (ItemInterface $item) {
            $item->expiresAfter(86400); // Durée de 1 jour (24h * 3600s)

            $check = ['isValid' => true, 'message' => []];

            // Check Signature
            if (!$this->signatureClient->status()) {
                $check = [
                    'isValid' => false,
                    'message' => ['service' => 'Signature', 'status' => 'Hors Service']
                ];
            }
            // Check Recherche
            elseif (!$this->searchClient->status()) {
                $check = [
                    'isValid' => false,
                    'message' => ['service' => 'Recherche', 'status' => 'Hors Service']
                ];
            }
            // Check Stripe
            elseif (!$this->stripeClient->status()) {
                $check = [
                    'isValid' => false,
                    'message' => ['service' => 'Stripe', 'status' => 'Hors Service']
                ];
            }

            // Si un service est HS, on envoie le mail une seule fois (lors de la mise en cache)
            if (!$check['isValid']) {
                $this->advertTech($check['message']);
            }

            return $check;
        });

        if (!$status['isValid']) {
            $response = new Response($this->environment->render('security/error.twig', [
                'message' => $status['message'],
            ]));
            $response->setStatusCode(Response::HTTP_FORBIDDEN);
            $requestEvent->setResponse($response);
        }
    }

    private function isWhitelisted(RequestEvent $event): bool
    {
        $request = $event->getRequest();
        $clientIp = $request->headers->get('cf-connecting-ip') ?? $request->getClientIp();

        return in_array($clientIp, self::WHITELISTED_IPS, true);
    }

    private function isDebugRoute(RequestEvent $event): bool
    {
        $path = $event->getRequest()->getPathInfo();
        return str_contains($path, "_wdt") || str_contains($path, "_profiler") || str_contains($path,'st_control');
    }

    public function advertTech(array $message): void
    {
        $this->mailer->send(
            'notification@siteconseil.fr',
            "Notification siteconseil",
            "[Intranet Ludikevent] - Accès impossible suite à une erreur de service",
            "mails/tech/noaccess.twig",
            ['message' => $message]
        );

        $this->discordWebhookService->send(null, [[
            'title' => '🚨 Alerte Service Intranet',
            'color' => 15158332, // Orange/Red
            'fields' => [
                [
                    'name' => 'Service',
                    'value' => $message['service'] ?? 'Inconnu',
                    'inline' => true
                ],
                [
                    'name' => 'Status',
                    'value' => $message['status'] ?? 'Erreur',
                    'inline' => true
                ],
            ],
            'timestamp' => date('c')
        ]]);
    }
}
