<?php

declare(strict_types=1);

namespace App\Controller\School;

use App\Service\School\SchoolContext;
use App\Entity\EcheancePaiement;
use App\Entity\Ecole;
use App\Entity\Etudiant;
use App\Entity\RegleFrais;
use App\Entity\TypeFrais;
use App\Form\Finance\RegleFraisType;
use App\Form\Finance\TypeFraisType;
use App\Repository\AnneeScolaireRepository;
use App\Repository\DepenseRepository;
use App\Repository\EcheancePaiementRepository;
use App\Repository\EtudiantRepository;
use App\Repository\MouvementCaisseRepository;
use App\Repository\PaiementRepository;
use App\Repository\RegleFraisRepository;
use App\Repository\TypeFraisRepository;
use App\Service\Finance\EcheanceGenerator;
use App\Service\Finance\FinanceCalculator;
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', name: 'school_')]
#[IsGranted('ROLE_ECOLE_ADMIN')]
final class FinanceController extends AbstractController
{
    public function __construct(private readonly SchoolContext $schoolContext)
    {
    }

    #[Route('/finance', name: 'finance_index', methods: ['GET'])]
    public function index(
        AnneeScolaireRepository $anneeRepository,
        DepenseRepository $depenseRepository,
        EcheancePaiementRepository $echeanceRepository,
        EtudiantRepository $etudiantRepository,
        MouvementCaisseRepository $mouvementRepository,
        FinanceCalculator $calculator,
        PaiementRepository $paiementRepository,
        EntityManagerInterface $em,
    ): Response {
        $ecole = $this->schoolContext->getEcole();
        $currentAnnee = $anneeRepository->findCurrentForEcole($ecole);
        $echeances = $echeanceRepository->findBy(['ecole' => $ecole, 'actif' => true], ['dateEcheance' => 'ASC', 'id' => 'ASC']);
        $totalDu = 0.0;
        $totalPaye = 0.0;
        $nonPayees = 0;
        $enRetard = 0;

        foreach ($echeances as $echeance) {
            $calculator->updateEcheanceStatus($echeance);
            $totalDu += (float) ($echeance->getMontantNet() ?? 0);
            $totalPaye += (float) $echeance->getMontantPaye();
            if ($echeance->getStatut() === EcheancePaiement::STATUT_NON_PAYE) {
                ++$nonPayees;
            }
            if ($echeance->getStatut() === EcheancePaiement::STATUT_EN_RETARD) {
                ++$enRetard;
            }
        }
        $em->flush();

        $studentsWithDebt = [];
        foreach ($etudiantRepository->findForEcole($ecole, null, $currentAnnee, 'current', $currentAnnee) as $etudiant) {
            $summary = $calculator->getStudentSummary($etudiant, $currentAnnee);
            if ($summary['reste'] <= 0) {
                continue;
            }
            $studentsWithDebt[] = ['etudiant' => $etudiant, 'summary' => $summary];
            if (count($studentsWithDebt) >= 8) {
                break;
            }
        }

        return $this->render('school/finance/index.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $currentAnnee,
            'cashSummary' => $calculator->getSchoolCashSummary($ecole),
            'recentPaiements' => $paiementRepository->findRecentByEcole($ecole, 6),
            'recentDepenses' => $depenseRepository->findRecentByEcole($ecole, 6),
            'recentMouvements' => $mouvementRepository->findRecentByEcole($ecole, 8),
            'yearlyCash' => $mouvementRepository->yearlySummaryByEcole($ecole),
            'summary' => [
                'totalDu' => $totalDu,
                'totalPaye' => $totalPaye,
                'reste' => max(0.0, $totalDu - $totalPaye),
                'nonPayees' => $nonPayees,
                'enRetard' => $enRetard,
            ],
            'studentsWithDebt' => $studentsWithDebt,
        ]);
    }

    #[Route('/finance/types-frais', name: 'finance_type_index', methods: ['GET'])]
    public function types(TypeFraisRepository $repository, AnneeScolaireRepository $anneeRepository): Response
    {
        $ecole = $this->schoolContext->getEcole();

        return $this->render('school/finance/type_index.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $anneeRepository->findCurrentForEcole($ecole),
            'types' => $repository->findBy(['ecole' => $ecole], ['ordre' => 'ASC', 'libelle' => 'ASC']),
        ]);
    }

    #[Route('/finance/types-frais/new', name: 'finance_type_new', methods: ['GET', 'POST'])]
    public function newType(Request $request, TypeFraisRepository $repository, AnneeScolaireRepository $anneeRepository, EntityManagerInterface $em): Response
    {
        $ecole = $this->schoolContext->getEcole();
        $type = (new TypeFrais())->setEcole($ecole)->setCode('NOUVEAU')->setLibelle('Nouveau frais')->setOrdre(1)->setActif(true);
        $form = $this->createForm(TypeFraisType::class, $type);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            if ($repository->findOneBy(['ecole' => $ecole, 'code' => $type->getCode()])) {
                $this->addFlash('danger', 'Ce code existe déjà pour cette madrassa.');
            } else {
                $em->persist($type);
                $em->flush();
                $this->addFlash('success', 'Le type de frais a été créé.');

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

        return $this->render('school/finance/type_form.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $anneeRepository->findCurrentForEcole($ecole),
            'form' => $form,
            'title' => 'Nouveau type de frais',
        ]);
    }

    #[Route('/finance/types-frais/{id}/edit', name: 'finance_type_edit', requirements: ['id' => '\\d+'], methods: ['GET', 'POST'])]
    public function editType(Request $request, TypeFrais $type, TypeFraisRepository $repository, AnneeScolaireRepository $anneeRepository, EntityManagerInterface $em): Response
    {
        $ecole = $this->schoolContext->getEcole();
        $this->schoolContext->assertSameSchool($type->getEcole());
        $form = $this->createForm(TypeFraisType::class, $type);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $existing = $repository->findOneBy(['ecole' => $ecole, 'code' => $type->getCode()]);
            if ($existing instanceof TypeFrais && $existing->getId() !== $type->getId()) {
                $this->addFlash('danger', 'Ce code existe déjà pour cette madrassa.');
            } else {
                $em->flush();
                $this->addFlash('success', 'Le type de frais a été mis à jour.');

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

        return $this->render('school/finance/type_form.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $anneeRepository->findCurrentForEcole($ecole),
            'form' => $form,
            'title' => 'Modifier un type de frais',
        ]);
    }

    #[Route('/finance/types-frais/{id}/delete', name: 'finance_type_delete', requirements: ['id' => '\\d+'], methods: ['POST'])]
    public function deleteType(Request $request, TypeFrais $type, RegleFraisRepository $regleRepository, EcheancePaiementRepository $echeanceRepository, EntityManagerInterface $em): Response
    {
        $this->schoolContext->assertSameSchool($type->getEcole());
        if ($this->isCsrfTokenValid('delete_type_frais_'.$type->getId(), (string) $request->request->get('_token'))) {
            if ($regleRepository->count(['typeFrais' => $type]) > 0 || $echeanceRepository->count(['typeFrais' => $type]) > 0) {
                $type->setActif(false);
                $this->addFlash('warning', 'Ce type est déjà utilisé. Il a été désactivé au lieu d’être supprimé.');
            } else {
                $em->remove($type);
                $this->addFlash('success', 'Le type de frais a été supprimé.');
            }
            $em->flush();
        }

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

    #[Route('/finance/regles-frais', name: 'finance_regle_index', methods: ['GET'])]
    public function regles(RegleFraisRepository $repository, AnneeScolaireRepository $anneeRepository): Response
    {
        $ecole = $this->schoolContext->getEcole();

        return $this->render('school/finance/regle_index.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $anneeRepository->findCurrentForEcole($ecole),
            'regles' => $repository->findBy(['ecole' => $ecole], ['id' => 'DESC']),
        ]);
    }

    #[Route('/finance/regles-frais/new', name: 'finance_regle_new', methods: ['GET', 'POST'])]
    public function newRegle(Request $request, AnneeScolaireRepository $anneeRepository, EntityManagerInterface $em): Response
    {
        $ecole = $this->schoolContext->getEcole();
        $regle = (new RegleFrais())->setEcole($ecole)->setMontant(0)->setActif(true);
        $form = $this->createForm(RegleFraisType::class, $regle, ['ecole' => $ecole]);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em->persist($regle);
            $em->flush();
            $this->addFlash('success', 'La règle de frais a été créée.');

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

        return $this->render('school/finance/regle_form.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $anneeRepository->findCurrentForEcole($ecole),
            'form' => $form,
            'title' => 'Nouvelle règle de frais',
        ]);
    }

    #[Route('/finance/regles-frais/{id}/edit', name: 'finance_regle_edit', requirements: ['id' => '\\d+'], methods: ['GET', 'POST'])]
    public function editRegle(Request $request, RegleFrais $regle, AnneeScolaireRepository $anneeRepository, EntityManagerInterface $em): Response
    {
        $ecole = $this->schoolContext->getEcole();
        $this->schoolContext->assertSameSchool($regle->getEcole());
        $form = $this->createForm(RegleFraisType::class, $regle, ['ecole' => $ecole]);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em->flush();
            $this->addFlash('success', 'La règle de frais a été mise à jour.');

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

        return $this->render('school/finance/regle_form.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $anneeRepository->findCurrentForEcole($ecole),
            'form' => $form,
            'title' => 'Modifier une règle de frais',
        ]);
    }

    #[Route('/finance/regles-frais/{id}/delete', name: 'finance_regle_delete', requirements: ['id' => '\\d+'], methods: ['POST'])]
    public function deleteRegle(Request $request, RegleFrais $regle, EcheancePaiementRepository $echeanceRepository, EntityManagerInterface $em): Response
    {
        $this->schoolContext->assertSameSchool($regle->getEcole());
        if ($this->isCsrfTokenValid('delete_regle_frais_'.$regle->getId(), (string) $request->request->get('_token'))) {
            if ($echeanceRepository->count(['regleFrais' => $regle]) > 0) {
                $regle->setActif(false);
                $this->addFlash('warning', 'Cette règle a déjà généré des échéances. Elle a été désactivée.');
            } else {
                $em->remove($regle);
                $this->addFlash('success', 'La règle de frais a été supprimée.');
            }
            $em->flush();
        }

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

    #[Route('/etudiants/{id}/finance', name: 'etudiant_finance', requirements: ['id' => '\\d+'], methods: ['GET'])]
    public function studentFinance(Etudiant $etudiant, FinanceCalculator $calculator, PaiementRepository $paiementRepository, EntityManagerInterface $em): Response
    {
        $ecole = $this->schoolContext->getEcole();
        $this->schoolContext->assertSameSchool($etudiant->getEcole());
        $summary = $calculator->getStudentSummary($etudiant, $etudiant->getAnneeScolaire());
        foreach ($summary['echeances'] as $echeance) {
            $calculator->updateEcheanceStatus($echeance);
        }
        $em->flush();
        $summary = $calculator->getStudentSummary($etudiant, $etudiant->getAnneeScolaire());

        return $this->render('school/finance/student.html.twig', [
            'ecole' => $ecole,
            'currentAnnee' => $etudiant->getAnneeScolaire(),
            'etudiant' => $etudiant,
            'summary' => $summary,
            'paiements' => $paiementRepository->findByStudent($etudiant),
        ]);
    }

    #[Route('/etudiants/{id}/finance/generer-echeances', name: 'etudiant_finance_generate', requirements: ['id' => '\\d+'], methods: ['POST'])]
    public function generateStudentEcheances(Request $request, Etudiant $etudiant, EcheanceGenerator $generator): Response
    {
        $this->schoolContext->assertSameSchool($etudiant->getEcole());
        if ($this->isCsrfTokenValid('generate_echeances_'.$etudiant->getId(), (string) $request->request->get('_token'))) {
            $created = $generator->generateForStudent($etudiant);
            $this->addFlash('success', sprintf('%d échéance(s) générée(s).', count($created)));
        }

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

}
