<?php

namespace App\Controller;

use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Attribute\Route;

class CspReportController extends AbstractController
{
    #[Route('/my-csp-report', name: 'app_csp_report_get', methods: ['GET'])]
    public function get(): Response
    {
        return new Response('', 204);
    }

    #[Route('/my-csp-report', name: 'app_csp_report', methods: ['POST'])]
    public function report(Request $request, MailerInterface $mailer, LoggerInterface $logger): Response
    {
        $data = $request->getContent();
        $report = empty($data) ? null : json_decode($data, true);

        if (null === $report || JSON_ERROR_NONE !== json_last_error()) {
            $logger->error('CSP Report: invalid or empty payload');

            return new Response('Invalid request', 400);
        }

        $details = $report['csp-report'] ?? $report;

        $sourceFile = $details['source-file'] ?? '';
        $blockedUri = $details['blocked-uri'] ?? '';
        $documentUri = $details['document-uri'] ?? '';
        $violatedDirective = $details['violated-directive'] ?? '';

        if ($this->isIgnoredViolation($sourceFile, $blockedUri, $documentUri)) {
            $logger->info('CSP Violation ignored (Extension or Local Dev): '.$sourceFile);

            return new Response('Report ignored', 204);
        }

        $logger->warning('REAL CSP VIOLATION: '.$data);
        $this->sendAlert($mailer, $logger, $report, $documentUri, $violatedDirective, $blockedUri, $sourceFile);

        return new Response('Report processed', 204);
    }

    private function isIgnoredViolation(string $sourceFile, string $blockedUri, string $documentUri): bool
    {
        return str_contains($sourceFile, 'extension://')
            || str_contains($sourceFile, 'chrome-extension')
            || str_contains($sourceFile, 'moz-extension')
            || str_contains($documentUri, '.local')
            || str_contains($sourceFile, 'localhost')
            || 'wasm-eval' === $blockedUri
            || 'inline' === $blockedUri && str_contains($sourceFile, 'node_modules')
            || 'about:blank' === $blockedUri;
    }

    /**
     * @param array<string, mixed> $report
     */
    private function sendAlert(MailerInterface $mailer, LoggerInterface $logger, array $report, string $documentUri, string $violatedDirective, string $blockedUri, string $sourceFile): void
    {
        $email = (new Email())
            ->from('security-notify@e-cosplay.fr')
            ->to($this->getParameter('admin_email'))
            ->subject('Alerte Securite : Violation CSP detectee')
            ->priority(Email::PRIORITY_HIGH)
            ->text(
                "Un rapport de violation CSP potentiellement critique a ete intercepte.\n\n".
                'Document: '.$documentUri."\n".
                'Directive violee: '.$violatedDirective."\n".
                'Element bloque: '.$blockedUri."\n".
                'Fichier source: '.$sourceFile."\n\n".
                "Details complets :\n".
                json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
            );

        try {
            $mailer->send($email);
        } catch (\Exception $e) {
            $logger->error('Failed to send CSP report email: '.$e->getMessage());
        }
    }
}
