<?php

namespace App\Controller;

use App\Entity\ScanSession;
use App\Entity\User;
use App\Repository\ScanSessionRepository;
use App\Repository\StockVehicleRepository;
use App\Service\ComparisonXlsxBuilder;
use App\Service\ConcessionsProvider;
use App\Service\InventoryComparator;
use App\Service\PdfReportBuilder;
use App\Service\StockComparisonXlsxBuilder;
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;

/**
 * Comparaison d'inventaires : deux inventaires entre eux, ou un inventaire scanné
 * confronté à la photo du stock importée dans Paramètres (table stock_vehicles).
 * Les concessions sont manipulées par ID (résolution en nom à l'affichage).
 * La confrontation au stock peut être restreinte au type VN (neuf) ou VO (occasion).
 */
#[IsGranted('ROLE_USER')]
final class ComparisonController extends AbstractController
{
    #[Route('/inventaires/comparer', name: 'app_compare', methods: ['GET'])]
    public function compare(
        Request $request,
        ScanSessionRepository $sessions,
        InventoryComparator $comparator,
        StockVehicleRepository $stockRepo,
        ConcessionsProvider $provider,
    ): Response {
        /** @var User $user */
        $user = $this->getUser();
        $scope = $user->scopeConcessions();

        // Ne proposer que les concessions ayant réellement un inventaire (dans le périmètre).
        $concessionList = $provider->labels($sessions->concessionsWithInventory($scope));
        $concession = trim((string) $request->query->get('concession', '')) ?: null;

        $inventories = [];
        if (null !== $concession) {
            $inventories = $sessions->findByConcessionInScope($concession, $scope);
        }

        // ─── Mode A : deux inventaires ───
        $idA = (string) $request->query->get('a', '');
        $idB = (string) $request->query->get('b', '');
        $diff = null;
        $sessionA = null;
        $sessionB = null;

        if ('' !== $idA && '' !== $idB) {
            $sessionA = $sessions->findOneInScope($idA, $scope);
            $sessionB = $sessions->findOneInScope($idB, $scope);
            if (null === $sessionA || null === $sessionB) {
                $this->addFlash('error', 'Inventaire introuvable ou hors de votre périmètre.');
            } elseif ($idA === $idB) {
                $this->addFlash('error', 'Veuillez choisir deux inventaires différents.');
                $diff = null;
            } else {
                $diff = $comparator->compare($sessionA, $sessionB);
            }
        }

        // ─── Mode B : inventaire vs photo du stock (importée dans Paramètres), filtrable VN/VO ───
        $stockSummary = $stockRepo->summary();
        // `vnvo` non transmis dans l'URL (lien direct) → on prendra par défaut le type de l'inventaire.
        $vnvoProvided = $request->query->has('vnvo');
        $vnvo = $request->query->get('vnvo');
        $vnvo = \in_array($vnvo, ['VN', 'VO'], true) ? $vnvo : null;
        $stockId = (string) $request->query->get('id', '');
        $stockDiff = null;
        $stockSession = null;
        $stockDates = [];

        if ('' !== $stockId) {
            $stockSession = $sessions->findOneInScope($stockId, $scope);
            if (null === $stockSession) {
                $this->addFlash('error', 'Veuillez choisir un inventaire valide de votre périmètre.');
            } elseif (0 === $stockSummary['count']) {
                $this->addFlash('error', 'Aucune photo du stock n’a été importée. Demandez à un administrateur de l’importer dans Paramètres.');
                $stockSession = null;
            } else {
                // Filtre VN/VO par défaut = type de l'inventaire scanné (si l'URL ne précise rien).
                // Un inventaire « VN & VO » (VNVO) reste sur « Tous » (le stock n'a que VN ou VO).
                if (!$vnvoProvided && \in_array($stockSession->getScanType(), ['VN', 'VO'], true)) {
                    $vnvo = $stockSession->getScanType();
                }
                $rows = $stockRepo->rowsForConcessions($stockSession->getConcessions(), $vnvo);
                if ([] === $rows) {
                    $this->addFlash('error', sprintf(
                        'La photo du stock ne contient aucun véhicule %spour la concession de l’inventaire (%s).',
                        null !== $vnvo ? $vnvo . ' ' : '',
                        implode(', ', $provider->names($stockSession->getConcessions())) ?: '-',
                    ));
                    $stockSession = null;
                } else {
                    $stockDiff = $comparator->compareToStock($stockSession, $rows);
                    $stockDates = self::stockDates($rows);
                }
            }

            // Lien direct « Comparer au stock » : pré-sélectionner la concession de l'inventaire.
            if (null !== $stockSession && null === $concession) {
                $concession = $stockSession->getConcessions()[0] ?? null;
                if (null !== $concession) {
                    $inventories = $sessions->findByConcessionInScope($concession, $scope);
                }
            }
        }

        return $this->render('page/comparison.html.twig', [
            'concessionList' => $concessionList,
            'concession' => $concession,
            'inventories' => $inventories,
            'sessionA' => $sessionA,
            'sessionB' => $sessionB,
            'idA' => $idA,
            'idB' => $idB,
            'diff' => $diff,
            'comparator' => $comparator,
            'stockSummary' => $stockSummary,
            'stockDiff' => $stockDiff,
            'stockSession' => $stockSession,
            'stockDates' => $stockDates,
            'stockId' => $stockId,
            'currentVnVo' => $vnvo,
        ]);
    }

    /**
     * Export Excel/PDF de la comparaison au stock, recalculée depuis la photo du stock en base.
     */
    #[Route('/inventaires/comparer/stock/export', name: 'app_compare_stock_export', methods: ['GET'])]
    public function stockExport(
        Request $request,
        ScanSessionRepository $sessions,
        InventoryComparator $comparator,
        StockVehicleRepository $stockRepo,
        StockComparisonXlsxBuilder $xlsx,
        PdfReportBuilder $pdf,
    ): Response {
        /** @var User $user */
        $user = $this->getUser();
        $scope = $user->scopeConcessions();

        $session = $sessions->findOneInScope((string) $request->query->get('id', ''), $scope);
        if (null === $session) {
            throw $this->createNotFoundException();
        }

        $vnvoProvided = $request->query->has('vnvo');
        $vnvo = $request->query->get('vnvo');
        $vnvo = \in_array($vnvo, ['VN', 'VO'], true) ? $vnvo : null;
        if (!$vnvoProvided && \in_array($session->getScanType(), ['VN', 'VO'], true)) {
            $vnvo = $session->getScanType();
        }

        $rows = $stockRepo->rowsForConcessions($session->getConcessions(), $vnvo);
        if ([] === $rows) {
            throw $this->createNotFoundException();
        }

        $diff = $comparator->compareToStock($session, $rows);
        $stockDate = implode(', ', self::stockDates($rows)) ?: null;
        $format = 'pdf' === $request->query->get('format') ? 'pdf' : 'xlsx';

        if ('pdf' === $format) {
            return new Response($pdf->buildStockComparison($session, $diff, $stockDate, $vnvo), Response::HTTP_OK, [
                'Content-Type' => 'application/pdf',
                'Content-Disposition' => 'attachment; filename="comparaison-stock.pdf"',
            ]);
        }

        return new Response($xlsx->build($session, $diff, $stockDate, $vnvo), Response::HTTP_OK, [
            'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'Content-Disposition' => 'attachment; filename="comparaison-stock.xlsx"',
        ]);
    }

    /**
     * Dates de stock distinctes des lignes retenues, formatées et triées chronologiquement.
     *
     * @param list<array{dateStock: ?\DateTimeImmutable}> $rows
     *
     * @return list<string>
     */
    private static function stockDates(array $rows): array
    {
        $dates = [];
        foreach ($rows as $r) {
            if ($r['dateStock'] instanceof \DateTimeImmutable) {
                $dates[$r['dateStock']->format('Y-m-d')] = $r['dateStock']->format('d/m/Y');
            }
        }
        ksort($dates);

        return array_values($dates);
    }

    #[Route('/inventaires/comparer/export', name: 'app_compare_export', methods: ['GET'])]
    public function export(
        Request $request,
        ScanSessionRepository $sessions,
        InventoryComparator $comparator,
        ComparisonXlsxBuilder $builder,
    ): Response {
        /** @var User $user */
        $user = $this->getUser();
        $scope = $user->scopeConcessions();

        $idA = (string) $request->query->get('a', '');
        $idB = (string) $request->query->get('b', '');
        if ($idA === $idB) {
            throw $this->createNotFoundException();
        }
        $sessionA = $sessions->findOneInScope($idA, $scope);
        $sessionB = $sessions->findOneInScope($idB, $scope);
        if (null === $sessionA || null === $sessionB) {
            throw $this->createNotFoundException();
        }

        $diff = $comparator->compare($sessionA, $sessionB);
        $content = $builder->build($sessionA, $sessionB, $diff);

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