<?php

declare(strict_types=1);

namespace App\Controller\School;

use App\Service\School\SchoolContext;
use App\Entity\Ecole;
use App\Entity\Etudiant;
use App\Entity\Inscription;
use App\Entity\InscriptionParcours;
use App\Entity\ParcoursEtudiant;
use App\Form\InscriptionAffectationType;
use App\Form\InscriptionRejectType;
use App\Repository\AnneeScolaireRepository;
use App\Repository\EtudiantRepository;
use App\Repository\InscriptionRepository;
use App\Repository\ParcoursEtudiantRepository;
use App\Repository\SectionRepository;
use App\Service\Finance\EcheanceGenerator;
use App\Service\MatriculeGenerator;
use App\Service\Pdf\InscriptionPdfGenerator;
use App\Service\Whatsapp\WhatsappNotificationService;
use Doctrine\ORM\EntityManagerInterface;
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;

#[Route('/school/inscriptions', name: 'school_inscription_')]
#[IsGranted('ROLE_ECOLE_ADMIN')]
final class InscriptionController extends AbstractController
{
    public function __construct(private readonly SchoolContext $schoolContext)
    {
    }

    #[Route('', name: 'index', methods: ['GET'])]
    public function index(Request $request, InscriptionRepository $repository, SectionRepository $sectionRepository, AnneeScolaireRepository $anneeRepository): Response
    {
        $ecole = $this->schoolContext->getEcole();
        $annees = $anneeRepository->findForEcole($ecole);
        $currentOfficialAnnee = $anneeRepository->findCurrentForEcole($ecole);
        $scope = $this->scope($request);
        $selectedAnnee = $this->selectedAnnee($request, $annees, $scope === 'current' ? $currentOfficialAnnee : null);
        $filters = [
            'statut' => $request->query->get('statut'),
            'section' => $request->query->get('section'),
            'type' => $request->query->get('type'),
            'q' => $request->query->get('q'),
        ];

        return $this->render('school/inscription/index.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $selectedAnnee,
            'anneeEnCours' => $currentOfficialAnnee,
            'annees' => $annees,
            'scope' => $scope,
            'inscriptions' => $repository->findForEcole($ecole, $filters, $selectedAnnee, $scope, $currentOfficialAnnee),
            'sections' => $sectionRepository->findForEcole($ecole),
            'filters' => $filters,
            'statuts' => $this->statusChoices(),
        ]);
    }

    #[Route('/{id}', name: 'show', requirements: ['id' => '\\d+'], methods: ['GET'])]
    public function show(Inscription $inscription): Response
    {
        $ecole = $this->schoolContext->getEcole();
        $this->schoolContext->assertSameSchool($inscription->getEcole());

        return $this->render('school/inscription/show.html.twig', ['ecole' => $ecole, 'currentAnnee' => $inscription->getAnneeScolaire(), 'inscription' => $inscription]);
    }

    #[Route('/{id}/edit', name: 'edit', requirements: ['id' => '\\d+'], methods: ['GET', 'POST'])]
    #[Route('/{id}/affecter', name: 'affecter', requirements: ['id' => '\\d+'], methods: ['GET', 'POST'])]
    public function affect(Request $request, Inscription $inscription, EntityManagerInterface $em): Response
    {
        $ecole = $this->schoolContext->getEcole();
        $this->schoolContext->assertSameSchool($inscription->getEcole());

        if (!$inscription->canBeAssigned()) {
            $this->addFlash('warning', 'Ce dossier ne peut plus être affecté dans son statut actuel.');

            return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
        }

        $this->primeFinalChoices($inscription);
        $this->prepareInscriptionParcoursForForm($inscription, $em);
        $form = $this->createForm(InscriptionAffectationType::class, $inscription, ['ecole' => $ecole]);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->normalizeInscriptionParcoursAfterAffectation($inscription);
            $this->assertRegistrationReferencesBelongToSchool($inscription, $ecole);
            $inscription->setStatut(Inscription::STATUT_A_AFFECTER);
            $em->flush();
            $this->addFlash('success', 'L’affectation a été enregistrée.');

            return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
        }

        return $this->render('school/inscription/affect.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $inscription->getAnneeScolaire(),
            'inscription' => $inscription,
            'form' => $form,
            'title' => 'Affecter la demande',
            'submitLabel' => 'Enregistrer l’affectation',
        ]);
    }

    #[Route('/{id}/marquer-a-tester', name: 'marquer_a_tester', requirements: ['id' => '\\d+'], methods: ['POST'])]
    public function markToTest(Request $request, Inscription $inscription, EntityManagerInterface $em): Response
    {
        $this->schoolContext->assertSameSchool($inscription->getEcole());
        if ($this->isCsrfTokenValid('mark_test_'.$inscription->getId(), (string) $request->request->get('_token'))) {
            if (!$inscription->canBeMarkedForTest()) {
                $this->addFlash('warning', 'Ce dossier ne peut plus être marqué à tester dans son statut actuel.');

                return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
            }

            $inscription->setStatut(Inscription::STATUT_A_TESTER);
            $em->flush();
            $this->addFlash('success', 'La demande est marquée à tester.');
        }

        return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
    }

    #[Route('/{id}/valider', name: 'valider', requirements: ['id' => '\\d+'], methods: ['GET', 'POST'])]
    public function validateRegistration(
        Request $request,
        Inscription $inscription,
        EntityManagerInterface $em,
        EtudiantRepository $etudiantRepository,
        ParcoursEtudiantRepository $parcoursEtudiantRepository,
        MatriculeGenerator $matriculeGenerator,
        EcheanceGenerator $echeanceGenerator,
        InscriptionPdfGenerator $pdfGenerator,
        WhatsappNotificationService $whatsappNotificationService,
    ): Response {
        $ecole = $this->schoolContext->getEcole();
        $this->schoolContext->assertSameSchool($inscription->getEcole());

        if (!$inscription->canBeValidated()) {
            $this->addFlash('warning', $inscription->isValidee() ? 'Cette inscription est déjà validée.' : 'Ce dossier ne peut pas être validé dans son statut actuel.');

            return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
        }

        $this->primeFinalChoices($inscription);
        $this->prepareInscriptionParcoursForForm($inscription, $em);
        $form = $this->createForm(InscriptionAffectationType::class, $inscription, ['ecole' => $ecole]);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->normalizeInscriptionParcoursAfterAffectation($inscription);
            $this->assertRegistrationReferencesBelongToSchool($inscription, $ecole);
            $etudiant = $this->resolveStudent($inscription, $etudiantRepository);
            $this->copyInscriptionToStudent($inscription, $etudiant);

            if (!$this->ensureStudentMatricule($inscription, $etudiant, $matriculeGenerator, $ecole)) {
                $this->addFlash('error', 'Impossible de valider un ancien étudiant sans matricule existant.');

                return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
            }

            $inscription
                ->setEtudiant($etudiant)
                ->setStatut(Inscription::STATUT_VALIDEE)
                ->setDateValidation(new \DateTimeImmutable())
                ->setMotifRejet(null);

            $em->persist($etudiant);
            $this->syncStudentParcours($inscription, $etudiant, $parcoursEtudiantRepository, $em);
            $em->flush();

            $createdEcheances = $echeanceGenerator->generateForStudent($etudiant, $inscription->getAnneeScolaire());

            try {
                $inscription->setFichePdfPath($pdfGenerator->generate($inscription, $etudiant));
                $em->flush();
            } catch (\Throwable $exception) {
                $this->addFlash('warning', 'Inscription validée, mais la fiche PDF n’a pas pu être générée : '.$exception->getMessage());
            }

            try {
                $whatsappNotificationService->notifyInscriptionValidated($inscription, $etudiant);
            } catch (\Throwable $exception) {
                $inscription->setWhatsappLastError($exception->getMessage());
                $em->flush();
            }

            $message = 'L’inscription a été validée et l’étudiant a été créé ou rattaché.';
            $message .= sprintf(' %d échéance(s) de paiement générée(s).', count($createdEcheances));
            $this->addFlash('success', $message);
            if ($inscription->getWhatsappLastError()) {
                $this->addFlash('warning', 'Inscription validée, mais WhatsApp non envoyé : '.$inscription->getWhatsappLastError());
            }

            return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
        }

        return $this->render('school/inscription/affect.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $inscription->getAnneeScolaire(),
            'inscription' => $inscription,
            'form' => $form,
            'title' => 'Valider l’inscription',
            'submitLabel' => 'Valider définitivement',
        ]);
    }

    #[Route('/{id}/rejeter', name: 'rejeter', requirements: ['id' => '\\d+'], methods: ['GET', 'POST'])]
    public function reject(Request $request, Inscription $inscription, EntityManagerInterface $em, WhatsappNotificationService $whatsappNotificationService): Response
    {
        $ecole = $this->schoolContext->getEcole();
        $this->schoolContext->assertSameSchool($inscription->getEcole());

        if (!$inscription->canBeRejected()) {
            $this->addFlash('warning', $inscription->isValidee() ? 'Une inscription validée ne peut pas être rejetée depuis cette action.' : 'Ce dossier ne peut pas être rejeté dans son statut actuel.');

            return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
        }

        $form = $this->createForm(InscriptionRejectType::class, $inscription);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $inscription
                ->setStatut(Inscription::STATUT_REJETEE)
                ->setDateRejet(new \DateTimeImmutable());
            $em->flush();
            try {
                $whatsappNotificationService->notifyInscriptionRejected($inscription);
            } catch (\Throwable $exception) {
                $inscription->setWhatsappLastError($exception->getMessage());
                $em->flush();
            }
            $this->addFlash('success', 'La demande a été rejetée.');
            if ($inscription->getWhatsappLastError()) {
                $this->addFlash('warning', 'Demande rejetée, mais WhatsApp non envoyé : '.$inscription->getWhatsappLastError());
            }

            return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
        }

        return $this->render('school/inscription/reject.html.twig', ['ecole' => $ecole, 'currentAnnee' => $inscription->getAnneeScolaire(), 'inscription' => $inscription, 'form' => $form]);
    }

    #[Route('/{id}/fiche-pdf', name: 'fiche_pdf', requirements: ['id' => '\\d+'], methods: ['POST'])]
    public function generatePdf(Request $request, Inscription $inscription, EntityManagerInterface $em, InscriptionPdfGenerator $pdfGenerator): Response
    {
        $this->schoolContext->assertSameSchool($inscription->getEcole());
        if ($this->isCsrfTokenValid('pdf_inscription_'.$inscription->getId(), (string) $request->request->get('_token'))) {
            try {
                $inscription->setFichePdfPath($pdfGenerator->generate($inscription, $inscription->getEtudiant()));
                $em->flush();
                $this->addFlash('success', 'La fiche PDF a été générée.');
            } catch (\Throwable $exception) {
                $this->addFlash('error', 'La fiche PDF n’a pas pu être générée : '.$exception->getMessage());
            }
        }

        return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
    }

    #[Route('/{id}/renvoyer-whatsapp', name: 'renvoyer_whatsapp', requirements: ['id' => '\\d+'], methods: ['POST'])]
    public function resendWhatsapp(Request $request, Inscription $inscription, EntityManagerInterface $em, WhatsappNotificationService $whatsappNotificationService): Response
    {
        $this->schoolContext->assertSameSchool($inscription->getEcole());

        if ($this->isCsrfTokenValid('resend_whatsapp_'.$inscription->getId(), (string) $request->request->get('_token'))) {
            try {
                if ($inscription->isValidee()) {
                    $etudiant = $inscription->getEtudiant();
                    if (!$etudiant instanceof Etudiant) {
                        $this->addFlash('warning', 'Impossible de renvoyer WhatsApp : aucun étudiant n’est rattaché au dossier validé.');

                        return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
                    }

                    $whatsappNotificationService->notifyInscriptionValidated($inscription, $etudiant);
                } elseif ($inscription->isRejetee()) {
                    $whatsappNotificationService->notifyInscriptionRejected($inscription);
                } else {
                    $whatsappNotificationService->notifyInscriptionSubmitted($inscription);
                }
            } catch (\Throwable $exception) {
                $inscription->setWhatsappLastError($exception->getMessage());
                $em->flush();
            }

            if ($inscription->getWhatsappLastError()) {
                $this->addFlash('warning', 'WhatsApp non envoyé : '.$inscription->getWhatsappLastError());
            } else {
                $this->addFlash('success', 'La notification WhatsApp a été renvoyée.');
            }
        }

        return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
    }


    #[Route('/{id}/delete', name: 'delete', requirements: ['id' => '\d+'], methods: ['POST'])]
    public function delete(Request $request, Inscription $inscription, EntityManagerInterface $em): Response
    {
        $this->schoolContext->assertSameSchool($inscription->getEcole());

        if ($this->isCsrfTokenValid('delete_inscription_'.$inscription->getId(), (string) $request->request->get('_token'))) {
            if (!$inscription->canBeDeleted()) {
                $this->addFlash('warning', 'Un dossier validé ne peut pas être supprimé depuis cette action.');

                return $this->redirectToRoute('school_inscription_show', ['id' => $inscription->getId()]);
            }

            // Suppression réelle du dossier d’inscription. L’étudiant validé éventuel est conservé.
            $this->deleteStoredPdf($inscription->getFichePdfPath());
            $em->remove($inscription);
            $em->flush();
            $this->addFlash('success', 'Le dossier d’inscription a été supprimé définitivement.');
        }

        return $this->redirectToRoute('school_inscription_index');
    }

    private function deleteStoredPdf(?string $path): void
    {
        if (!$path) {
            return;
        }

        $normalizedPath = ltrim($path, '/');
        if (!str_starts_with($normalizedPath, 'uploads/inscriptions/')) {
            return;
        }

        $absolutePath = rtrim((string) $this->getParameter('kernel.project_dir'), '/').'/public/'.$normalizedPath;
        if (is_file($absolutePath)) {
            @unlink($absolutePath);
        }
    }

    private function assertRegistrationReferencesBelongToSchool(Inscription $inscription, Ecole $ecole): void
    {
        foreach ([
            $inscription->getAnneeScolaire(),
            $inscription->getSectionSouhaitee(),
            $inscription->getNiveauSouhaite(),
            $inscription->getClasseSouhaitee(),
            $inscription->getSectionFinale(),
            $inscription->getNiveauFinal(),
            $inscription->getClasseFinale(),
        ] as $subject) {
            $this->assertBelongsToSchool($subject, $ecole);
        }

        foreach ($inscription->getParcours() as $parcours) {
            $this->assertBelongsToSchool($parcours->getAnneeScolaire(), $ecole);
            $this->assertBelongsToSchool($parcours->getSectionSouhaitee(), $ecole);
            $this->assertBelongsToSchool($parcours->getNiveauSouhaite(), $ecole);
            $this->assertBelongsToSchool($parcours->getClasseSouhaitee(), $ecole);
            $this->assertBelongsToSchool($parcours->getSectionFinale(), $ecole);
            $this->assertBelongsToSchool($parcours->getNiveauFinal(), $ecole);
            $this->assertBelongsToSchool($parcours->getClasseFinale(), $ecole);
        }
    }

    private function assertBelongsToSchool(?object $subject, Ecole $ecole): void
    {
        if ($subject === null) {
            return;
        }

        if (!method_exists($subject, 'getEcole')) {
            throw new \LogicException(sprintf('Impossible de vérifier la madrassa de "%s".', $subject::class));
        }

        $subjectSchool = $subject->getEcole();
        if (!$subjectSchool instanceof Ecole) {
            return;
        }

        if ($subjectSchool->getId() !== null && $ecole->getId() !== null && $subjectSchool->getId() === $ecole->getId()) {
            return;
        }

        if ($subjectSchool === $ecole) {
            return;
        }

        throw $this->createAccessDeniedException('Un élément sélectionné n’appartient pas à cette madrassa.');
    }

    private function resolveStudent(Inscription $inscription, EtudiantRepository $repository): Etudiant
    {
        $linkedStudent = $inscription->getEtudiant();
        if ($linkedStudent instanceof Etudiant) {
            $this->schoolContext->assertSameSchool($linkedStudent);

            return $linkedStudent;
        }

        if ($inscription->getTypeCandidat() === Inscription::TYPE_ANCIEN && $inscription->getAncienMatricule()) {
            $existing = $repository->findOneBy([
                'ecole' => $inscription->getEcole(),
                'matricule' => $inscription->getAncienMatricule(),
            ]);
            if ($existing instanceof Etudiant) {
                return $existing;
            }
        }

        $ecole = $inscription->getEcole();
        if (!$ecole instanceof Ecole) {
            throw new \LogicException('Impossible de rattacher une inscription sans madrassa.');
        }

        $contactMatch = $repository->findOneMatchingContactForEcole(
            $ecole,
            $inscription->getNom(),
            $inscription->getPrenom(),
            $inscription->getTelephonePrincipal(),
            $inscription->getTelephoneWhatsapp(),
        );
        if ($contactMatch instanceof Etudiant) {
            return $contactMatch;
        }

        return (new Etudiant())->setEcole($ecole)->setAncien($inscription->getTypeCandidat() === Inscription::TYPE_ANCIEN);
    }

    private function copyInscriptionToStudent(Inscription $inscription, Etudiant $etudiant): void
    {
        $inscription
            ->setSectionFinale($inscription->getSectionFinale() ?: $inscription->getSectionSouhaitee())
            ->setNiveauFinal($inscription->getNiveauFinal() ?: $inscription->getNiveauSouhaite())
            ->setClasseFinale($inscription->getClasseFinale() ?: $inscription->getClasseSouhaitee());

        $etudiant
            ->setNom($inscription->getNom() ?: '')
            ->setPrenom($inscription->getPrenom())
            ->setSexe($inscription->getSexe())
            ->setDateNaissance($inscription->getDateNaissance())
            ->setLieuNaissance($inscription->getLieuNaissance())
            ->setSituationMatrimoniale($inscription->getSituationMatrimoniale())
            ->setTelephonePrincipal($inscription->getTelephonePrincipal())
            ->setTelephoneWhatsapp($inscription->getTelephoneWhatsapp())
            ->setAutreContact($inscription->getAutreContact())
            ->setEmail($inscription->getEmail())
            ->setAdresse($inscription->getAdresse())
            ->setADesEnfants($inscription->hasEnfants())
            ->setJoursDisponibles($inscription->getJoursDisponibles())
            ->setPlageHoraireSouhaitee($inscription->getPlageHoraireSouhaitee())
            ->setMatriculeTemporaire($inscription->getMatriculeTemporaire())
            ->setAnneeScolaire($inscription->getAnneeScolaire())
            ->setActif(true);
    }

    private function syncStudentParcours(Inscription $inscription, Etudiant $etudiant, ParcoursEtudiantRepository $repository, EntityManagerInterface $em): void
    {
        $parcoursInscription = $this->activeInscriptionParcours($inscription, $em);
        if ($parcoursInscription === []) {
            return;
        }

        $principal = $this->principalInscriptionParcours($parcoursInscription);
        if ($principal instanceof InscriptionParcours) {
            $this->syncCompatibilityParcours($inscription, $etudiant, $principal);
        }

        $seenClasses = [];
        foreach ($parcoursInscription as $parcours) {
            $annee = $parcours->getAnneeScolaire() ?: $inscription->getAnneeScolaire();
            $section = $parcours->getSectionFinale() ?: $parcours->getSectionSouhaitee();
            $niveau = $parcours->getNiveauFinal() ?: $parcours->getNiveauSouhaite();
            $classe = $parcours->getClasseFinale() ?: $parcours->getClasseSouhaitee();

            if (!$section && !$niveau && !$classe) {
                continue;
            }

            $classKey = $classe ? (($annee?->getId() ?: 'null').':'.$classe->getId()) : null;
            if ($classKey && isset($seenClasses[$classKey])) {
                continue;
            }

            if ($classe && $etudiant->getId() && $repository->existsActiveForStudentClass($etudiant, $annee, $classe)) {
                continue;
            }

            if ($classKey) {
                $seenClasses[$classKey] = true;
            }

            $parcoursEtudiant = (new ParcoursEtudiant())
                ->setEcole($etudiant->getEcole() ?: $inscription->getEcole())
                ->setAnneeScolaire($annee)
                ->setSection($section)
                ->setNiveau($niveau)
                ->setClasse($classe)
                ->setInscription($inscription)
                ->setInscriptionParcours($parcours)
                ->setLangue($parcours->getLangueSouhaitee())
                ->setMode($parcours->getModeSouhaite())
                ->setTarifApplique($parcours->getTarifPropose() ?: $classe?->getTarifDefaut())
                ->setPrincipal($parcours === $principal)
                ->setActif(true)
                ->setStatut(ParcoursEtudiant::STATUT_ACTIF)
                ->setObservation($parcours->getObservation());

            $etudiant->addParcours($parcoursEtudiant);
            $em->persist($parcoursEtudiant);
        }
    }

    private function prepareInscriptionParcoursForForm(Inscription $inscription, EntityManagerInterface $em): void
    {
        $ecole = $inscription->getEcole();
        if (!$ecole) {
            throw new \LogicException('Impossible de préparer les parcours sans madrassa.');
        }

        if ($inscription->getParcours()->isEmpty()) {
            $fallback = (new InscriptionParcours())
                ->setEcole($ecole)
                ->setAnneeScolaire($inscription->getAnneeScolaire())
                ->setSectionSouhaitee($inscription->getSectionSouhaitee())
                ->setNiveauSouhaite($inscription->getNiveauSouhaite())
                ->setClasseSouhaitee($inscription->getClasseSouhaitee())
                ->setSectionFinale($inscription->getSectionFinale() ?: $inscription->getSectionSouhaitee())
                ->setNiveauFinal($inscription->getNiveauFinal() ?: $inscription->getNiveauSouhaite())
                ->setClasseFinale($inscription->getClasseFinale() ?: $inscription->getClasseSouhaitee())
                ->setLangueSouhaitee($inscription->getLangueSouhaitee())
                ->setModeSouhaite($inscription->getModeSouhaite())
                ->setPrincipal(true)
                ->setActif(true)
                ->setOrdre(1);
            $inscription->addParcours($fallback);
            $em->persist($fallback);
        }

        $order = 1;
        foreach ($inscription->getParcours() as $parcours) {
            $parcours
                ->setEcole($parcours->getEcole() ?: $ecole)
                ->setAnneeScolaire($parcours->getAnneeScolaire() ?: $inscription->getAnneeScolaire())
                ->setSectionFinale($parcours->getSectionFinale() ?: $parcours->getSectionSouhaitee())
                ->setNiveauFinal($parcours->getNiveauFinal() ?: $parcours->getNiveauSouhaite())
                ->setClasseFinale($parcours->getClasseFinale() ?: $parcours->getClasseSouhaitee())
                ->setOrdre($parcours->getOrdre() ?: $order)
                ->setActif($parcours->isActif());
            ++$order;
        }
    }

    private function normalizeInscriptionParcoursAfterAffectation(Inscription $inscription): void
    {
        $firstActive = null;
        $selectedPrincipal = null;
        $order = 1;

        foreach ($inscription->getParcours() as $parcours) {
            if (!$this->hasAffectationParcoursContent($parcours)) {
                $inscription->removeParcours($parcours);
                continue;
            }

            $parcours
                ->setEcole($parcours->getEcole() ?: $inscription->getEcole())
                ->setAnneeScolaire($parcours->getAnneeScolaire() ?: $inscription->getAnneeScolaire())
                ->setSectionFinale($parcours->getSectionFinale() ?: $parcours->getSectionSouhaitee())
                ->setNiveauFinal($parcours->getNiveauFinal() ?: $parcours->getNiveauSouhaite())
                ->setClasseFinale($parcours->getClasseFinale() ?: $parcours->getClasseSouhaitee())
                ->setOrdre($order++);

            if (!$parcours->isActif()) {
                $parcours->setPrincipal(false);
                continue;
            }

            $firstActive ??= $parcours;
            if ($parcours->isPrincipal() && !$selectedPrincipal) {
                $selectedPrincipal = $parcours;
            }
        }

        $principal = $selectedPrincipal ?: $firstActive;
        foreach ($inscription->getParcours() as $parcours) {
            $parcours->setPrincipal($parcours === $principal);
        }

        if ($principal instanceof InscriptionParcours) {
            $inscription
                ->setSectionFinale($principal->getSectionFinale() ?: $principal->getSectionSouhaitee())
                ->setNiveauFinal($principal->getNiveauFinal() ?: $principal->getNiveauSouhaite())
                ->setClasseFinale($principal->getClasseFinale() ?: $principal->getClasseSouhaitee());
        }
    }

    private function hasAffectationParcoursContent(InscriptionParcours $parcours): bool
    {
        return $parcours->getSectionSouhaitee()
            || $parcours->getNiveauSouhaite()
            || $parcours->getClasseSouhaitee()
            || $parcours->getSectionFinale()
            || $parcours->getNiveauFinal()
            || $parcours->getClasseFinale()
            || $parcours->getTarifPropose()
            || $parcours->getObservation()
            || $parcours->getLangueSouhaitee()
            || $parcours->getModeSouhaite();
    }

    /** @return list<InscriptionParcours> */
    private function activeInscriptionParcours(Inscription $inscription, EntityManagerInterface $em): array
    {
        $ecole = $inscription->getEcole();
        if (!$ecole) {
            throw new \LogicException('Impossible de créer un parcours sans madrassa.');
        }

        if ($inscription->getParcours()->isEmpty()) {
            $fallback = (new InscriptionParcours())
                ->setEcole($ecole)
                ->setAnneeScolaire($inscription->getAnneeScolaire())
                ->setSectionSouhaitee($inscription->getSectionSouhaitee())
                ->setNiveauSouhaite($inscription->getNiveauSouhaite())
                ->setClasseSouhaitee($inscription->getClasseSouhaitee())
                ->setSectionFinale($inscription->getSectionFinale() ?: $inscription->getSectionSouhaitee())
                ->setNiveauFinal($inscription->getNiveauFinal() ?: $inscription->getNiveauSouhaite())
                ->setClasseFinale($inscription->getClasseFinale() ?: $inscription->getClasseSouhaitee())
                ->setLangueSouhaitee($inscription->getLangueSouhaitee())
                ->setModeSouhaite($inscription->getModeSouhaite())
                ->setPrincipal(true)
                ->setActif(true)
                ->setOrdre(1);
            $inscription->addParcours($fallback);
            $em->persist($fallback);
        }

        $active = [];
        foreach ($inscription->getParcours() as $parcours) {
            if (!$parcours->isActif()) {
                continue;
            }

            $parcours
                ->setEcole($parcours->getEcole() ?: $ecole)
                ->setAnneeScolaire($parcours->getAnneeScolaire() ?: $inscription->getAnneeScolaire())
                ->setSectionFinale($parcours->getSectionFinale() ?: $parcours->getSectionSouhaitee())
                ->setNiveauFinal($parcours->getNiveauFinal() ?: $parcours->getNiveauSouhaite())
                ->setClasseFinale($parcours->getClasseFinale() ?: $parcours->getClasseSouhaitee());

            $active[] = $parcours;
        }

        return $active;
    }

    /** @param list<InscriptionParcours> $parcours */
    private function principalInscriptionParcours(array $parcours): ?InscriptionParcours
    {
        foreach ($parcours as $item) {
            if ($item->isPrincipal()) {
                return $item;
            }
        }

        return $parcours[0] ?? null;
    }

    private function syncCompatibilityParcours(Inscription $inscription, Etudiant $etudiant, InscriptionParcours $parcours): void
    {
        $section = $parcours->getSectionFinale() ?: $parcours->getSectionSouhaitee();
        $niveau = $parcours->getNiveauFinal() ?: $parcours->getNiveauSouhaite();
        $classe = $parcours->getClasseFinale() ?: $parcours->getClasseSouhaitee();
        $annee = $parcours->getAnneeScolaire() ?: $inscription->getAnneeScolaire();

        $inscription
            ->setSectionFinale($section)
            ->setNiveauFinal($niveau)
            ->setClasseFinale($classe);

        $etudiant
            ->setAnneeScolaire($annee)
            ->setSection($section)
            ->setNiveau($niveau)
            ->setClasse($classe);
    }

    private function ensureStudentMatricule(Inscription $inscription, Etudiant $etudiant, MatriculeGenerator $matriculeGenerator, Ecole $ecole): bool
    {
        if ($etudiant->getMatricule()) {
            return true;
        }

        if ($inscription->getTypeCandidat() === Inscription::TYPE_ANCIEN) {
            if (!$inscription->getAncienMatricule()) {
                return false;
            }

            $etudiant->setMatricule($inscription->getAncienMatricule());

            return true;
        }

        $etudiant->setMatricule($matriculeGenerator->generateMatriculeDefinitif($ecole));

        return $etudiant->getMatricule() !== null;
    }

    private function primeFinalChoices(Inscription $inscription): void
    {
        $inscription
            ->setSectionFinale($inscription->getSectionFinale() ?: $inscription->getSectionSouhaitee())
            ->setNiveauFinal($inscription->getNiveauFinal() ?: $inscription->getNiveauSouhaite())
            ->setClasseFinale($inscription->getClasseFinale() ?: $inscription->getClasseSouhaitee());
    }

    /** @return array<string, string> */
    private function statusChoices(): array
    {
        return [
            'Soumise' => Inscription::STATUT_SOUMISE,
            'À tester' => Inscription::STATUT_A_TESTER,
            'À affecter' => Inscription::STATUT_A_AFFECTER,
            'Validée' => Inscription::STATUT_VALIDEE,
            'Rejetée' => Inscription::STATUT_REJETEE,
            'Annulée' => Inscription::STATUT_ANNULEE,
        ];
    }


    private function selectedAnnee(Request $request, array $annees, $current)
    {
        $id = $request->query->getInt('annee');
        if ($id > 0) {
            foreach ($annees as $annee) {
                if ($annee->getId() === $id) {
                    return $annee;
                }
            }
        }

        return $current;
    }

    private function scope(Request $request): string
    {
        $scope = (string) $request->query->get('scope', 'current');

        return in_array($scope, ['current', 'archives', 'all'], true) ? $scope : 'current';
    }
}
