<?php

declare(strict_types=1);

namespace App\Repository;

use App\Entity\AnneeScolaire;
use App\Entity\Ecole;
use App\Entity\ParcoursEtudiant;
use App\Entity\RegleFrais;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/** @extends ServiceEntityRepository<RegleFrais> */
final class RegleFraisRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, RegleFrais::class);
    }

    /** @return list<RegleFrais> */
    public function findActiveByEcole(Ecole $ecole): array
    {
        return $this->createQueryBuilder('r')
            ->andWhere('r.ecole = :ecole')
            ->andWhere('r.actif = :actif')
            ->setParameter('ecole', $ecole)
            ->setParameter('actif', true)
            ->orderBy('r.id', 'DESC')
            ->getQuery()
            ->getResult();
    }

    /** @return list<RegleFrais> */
    public function findByEcoleAndYear(Ecole $ecole, ?AnneeScolaire $anneeScolaire): array
    {
        $qb = $this->createQueryBuilder('r')
            ->andWhere('r.ecole = :ecole')
            ->setParameter('ecole', $ecole)
            ->orderBy('r.id', 'DESC');

        $anneeScolaire
            ? $qb->andWhere('r.anneeScolaire = :annee')->setParameter('annee', $anneeScolaire)
            : $qb->andWhere('r.anneeScolaire IS NULL');

        return $qb->getQuery()->getResult();
    }

    /** @return list<RegleFrais> */
    public function findApplicableForParcours(ParcoursEtudiant $parcours): array
    {
        $ecole = $parcours->getEcole();
        $annee = $parcours->getAnneeScolaire();
        $section = $parcours->getSection();
        $classe = $parcours->getClasse();

        $qb = $this->createQueryBuilder('r')
            ->andWhere('r.ecole = :ecole')
            ->andWhere('r.actif = :actif')
            ->andWhere('(r.anneeScolaire IS NULL'.($annee ? ' OR r.anneeScolaire = :annee' : '').')')
            ->andWhere('(r.section IS NULL'.($section ? ' OR r.section = :section' : '').')')
            ->andWhere('(r.classe IS NULL'.($classe ? ' OR r.classe = :classe' : '').')')
            ->setParameter('ecole', $ecole)
            ->setParameter('actif', true);

        if ($annee) {
            $qb->setParameter('annee', $annee);
        }
        if ($section) {
            $qb->setParameter('section', $section);
        }
        if ($classe) {
            $qb->setParameter('classe', $classe);
        }

        $rules = $qb->getQuery()->getResult();
        usort($rules, fn (RegleFrais $a, RegleFrais $b): int => $this->score($b, $parcours) <=> $this->score($a, $parcours));

        $selectedByType = [];
        foreach ($rules as $rule) {
            $typeId = $rule->getTypeFrais()?->getId();
            if ($typeId === null || isset($selectedByType[$typeId])) {
                continue;
            }

            $selectedByType[$typeId] = $rule;
        }

        return array_values($selectedByType);
    }

    private function score(RegleFrais $regle, ParcoursEtudiant $parcours): int
    {
        $hasYear = $regle->getAnneeScolaire() !== null && $regle->getAnneeScolaire() === $parcours->getAnneeScolaire();
        $hasClass = $regle->getClasse() !== null && $regle->getClasse() === $parcours->getClasse();
        $hasSection = $regle->getSection() !== null && $regle->getSection() === $parcours->getSection();

        if ($hasClass && $hasYear) {
            return 60;
        }
        if ($hasSection && $hasYear) {
            return 50;
        }
        if ($hasYear && $regle->getClasse() === null && $regle->getSection() === null) {
            return 40;
        }
        if ($hasClass) {
            return 30;
        }
        if ($hasSection) {
            return 20;
        }

        return 10;
    }
}
