<?php

namespace App\Controller;

use App\Entity\ScanSession;
use App\Entity\User;
use App\Repository\ScanSessionRepository;
use App\Service\ConcessionsProvider;
use App\Service\PdfReportBuilder;
use App\Service\XlsxReportBuilder;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

/**
 * Export téléchargeable des résultats de scan (CSV / Excel).
 * Réutilise les builders serveur (marque, formatage). Concessions = celles de l'utilisateur.
 */
#[IsGranted('ROLE_USER')]
final class ExportController extends AbstractController
{
    public function __construct(
        private readonly ScanSessionRepository $sessions,
        private readonly ConcessionsProvider $concessions,
    ) {
    }

    #[Route('/api/export/xlsx', name: 'app_export_xlsx', methods: ['POST'])]
    public function xlsx(Request $request, XlsxReportBuilder $builder): Response
    {
        $ctx = $this->extractContext($request);
        $content = $builder->build($ctx['results'], $ctx['concessionStr'], $ctx['locationNote'], $ctx['scannedBy']);

        return new Response($content, Response::HTTP_OK, [
            'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'Content-Disposition' => 'attachment; filename="scan-vehicules.xlsx"',
        ]);
    }

    /**
     * Rapport PDF « avec images » : une ligne par véhicule, photos plaque + VIN, immat, VIN, heure.
     * Réservé aux inventaires validés (comme l'export PDF standard) et au chemin {sessionId}
     * (les images sont nécessaires, donc pas de génération depuis des résultats inline).
     */
    #[Route('/api/export/pdf-photos', name: 'app_export_pdf_photos', methods: ['POST'])]
    public function pdfPhotos(Request $request, PdfReportBuilder $builder): Response
    {
        $data = json_decode($request->getContent(), true);
        $sessionId = \is_array($data) ? ($data['sessionId'] ?? null) : null;
        if (!\is_string($sessionId) || '' === $sessionId) {
            return new Response('Requête invalide.', Response::HTTP_BAD_REQUEST);
        }

        /** @var User $user */
        $user = $this->getUser();
        $session = $this->sessions->findOneInScope($sessionId, $user->scopeConcessions());
        if (null === $session) {
            throw $this->createNotFoundException();
        }
        if (ScanSession::STATUS_VALIDE !== $session->getStatus()) {
            return new Response('Rapport disponible uniquement lorsque l’inventaire est validé.', Response::HTTP_FORBIDDEN);
        }
        // Photos sur S3 : le serveur OVH ne peut pas lire les octets (pas d'accès réseau S3),
        // or ce rapport embarque les images. Indisponible pour les inventaires migrés S3.
        if ($session->isOnS3()) {
            return new Response('Rapport « PDF + photos » indisponible pour les inventaires stockés sur S3 (les photos ne sont pas accessibles côté serveur). Utilisez l’export Excel ou le PDF standard.', Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        $conc = $this->concessions->names($session->getConcessions());
        $content = $builder->buildPhotoReport($session, [] !== $conc ? implode(' / ', $conc) : '-');

        return new Response($content, Response::HTTP_OK, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'attachment; filename="rapport-photos.pdf"',
        ]);
    }

    /**
     * Rapport « avec images » version NAVIGATEUR, pour les inventaires stockés sur S3.
     *
     * Le serveur OVH n'a pas d'accès réseau à S3 : il ne peut donc pas embarquer les octets des
     * photos dans un PDF (cf. pdfPhotos ci-dessus). On rend à la place une page HTML imprimable
     * dont les <img> pointent vers des URL S3 pré-signées (le navigateur, lui, sait joindre S3 ;
     * un simple affichage d'image ne nécessite pas de CORS). L'utilisateur fait « Enregistrer en
     * PDF » depuis la boîte d'impression (déclenchée automatiquement une fois les photos chargées).
     *
     * Réservé aux inventaires validés (comme l'export PDF et le rapport PDF+photos serveur) : si
     * l'inventaire n'est pas validé, on rend une page d'information (statut 403) au lieu du rapport.
     *
     * Par défaut la page génère et TÉLÉCHARGE directement un PDF côté navigateur (jsPDF) : les
     * photos sont récupérées via leurs URL S3 pré-signées puis réduites (VIN pleine résolution,
     * plaque /8) avant embarquage. Cela suppose le CORS activé (le navigateur doit pouvoir lire les
     * pixels). En repli, ?print=1 rend l'ancienne page imprimable (window.print()).
     */
    #[Route('/inventaires/{id}/rapport-photos', name: 'app_report_photos_web', methods: ['GET'])]
    public function photosWeb(string $id, Request $request): Response
    {
        /** @var User $user */
        $user = $this->getUser();
        $session = $this->sessions->findOneInScope($id, $user->scopeConcessions());
        if (null === $session) {
            throw $this->createNotFoundException();
        }

        $conc = $this->concessions->names($session->getConcessions());

        // Règle métier : l'export « avec images » n'est disponible que pour un inventaire validé.
        $blockedReason = ScanSession::STATUS_VALIDE !== $session->getStatus()
            ? 'L’export avec images n’est disponible que lorsque l’inventaire est validé.'
            : null;

        $response = $this->render('report/photos_print.html.twig', [
            'session' => $session,
            'concessionStr' => [] !== $conc ? implode(' / ', $conc) : '-',
            'printMode' => $request->query->getBoolean('print'),
            'blockedReason' => $blockedReason,
        ]);
        if (null !== $blockedReason) {
            $response->setStatusCode(Response::HTTP_FORBIDDEN);
        }
        // Page de génération dynamique : ne jamais la servir depuis le cache navigateur
        // (sinon une correction du template/script n'est pas prise en compte au rechargement).
        $response->headers->set('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');

        return $response;
    }

    /**
     * Soit {sessionId} (charge depuis la DB : results + concessions snapshot + lieu + auteur),
     * soit {results} inline (concessions = celles courantes du User, pas de lieu, auteur = user courant).
     *
     * Le champ {status} n'est renseigné que pour le chemin {sessionId} (sinon null) :
     * il sert à réserver l'export PDF aux inventaires validés.
     *
     * @return array{results: array<int, array<string, mixed>>, concessionStr: string, locationNote: ?string, scannedBy: ?string, label: string, createdAt: ?\DateTimeImmutable, status: ?string}
     */
    private function extractContext(Request $request): array
    {
        $empty = ['results' => [], 'concessionStr' => '-', 'locationNote' => null, 'scannedBy' => null, 'label' => 'Inventaire', 'createdAt' => null, 'status' => null];

        $data = json_decode($request->getContent(), true);
        if (!\is_array($data)) {
            return $empty;
        }

        if (!empty($data['sessionId']) && \is_string($data['sessionId'])) {
            /** @var User $user */
            $user = $this->getUser();
            $session = $this->sessions->findOneInScope($data['sessionId'], $user->scopeConcessions());
            if (null === $session) {
                return $empty;
            }
            $conc = $this->concessions->names($session->getConcessions());

            return [
                'results' => $session->getResults(),
                'concessionStr' => [] !== $conc ? implode(' / ', $conc) : '-',
                'locationNote' => $session->getLocationNote(),
                'scannedBy' => $session->getUserEmail(),
                'label' => $session->getLabel(),
                'createdAt' => $session->getCreatedAt(),
                'status' => $session->getStatus(),
            ];
        }

        /** @var User $user */
        $user = $this->getUser();

        return [
            'results' => \is_array($data['results'] ?? null) ? $data['results'] : [],
            'concessionStr' => $this->concessionStr(),
            'locationNote' => null,
            'scannedBy' => $user->getUserIdentifier(),
            'label' => \is_string($data['label'] ?? null) && '' !== $data['label'] ? $data['label'] : 'Rapport de scan',
            'createdAt' => null,
            'status' => null,
        ];
    }

    private function concessionStr(): string
    {
        /** @var User $user */
        $user = $this->getUser();
        $concessions = $this->concessions->names($user->getConcessions());

        return [] !== $concessions ? implode(' / ', $concessions) : '-';
    }
}
