<?php

declare(strict_types=1);

namespace App\Repository;

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

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

    public function sumEntreesByEcole(Ecole $ecole): float
    {
        return $this->sumByType($ecole, MouvementCaisse::TYPE_ENTREE, null);
    }

    public function sumSortiesByEcole(Ecole $ecole): float
    {
        return $this->sumByType($ecole, MouvementCaisse::TYPE_SORTIE, null);
    }

    public function sumByEcoleAndType(Ecole $ecole, string $type, ?AnneeScolaire $anneeScolaire = null): float
    {
        return $this->sumByType($ecole, $type, $anneeScolaire);
    }

    /** @return list<MouvementCaisse> */
    public function findRecentByEcole(Ecole $ecole, int $limit = 10): array
    {
        return $this->createQueryBuilder('m')
            ->andWhere('m.ecole = :ecole')
            ->setParameter('ecole', $ecole)
            ->orderBy('m.dateMouvement', 'DESC')
            ->addOrderBy('m.id', 'DESC')
            ->setMaxResults($limit)
            ->getQuery()
            ->getResult();
    }

    /** @return list<array{annee: string, entrees: float, sorties: float, solde: float}> */
    public function yearlySummaryByEcole(Ecole $ecole): array
    {
        $rows = $this->createQueryBuilder('m')
            ->select('a.id AS anneeId, a.libelle AS annee, m.type AS type, COALESCE(SUM(m.montant), 0) AS total')
            ->leftJoin('m.anneeScolaire', 'a')
            ->andWhere('m.ecole = :ecole')
            ->setParameter('ecole', $ecole)
            ->groupBy('a.id')
            ->addGroupBy('a.libelle')
            ->addGroupBy('a.dateDebut')
            ->addGroupBy('m.type')
            ->orderBy('a.dateDebut', 'DESC')
            ->addOrderBy('a.id', 'DESC')
            ->getQuery()
            ->getArrayResult();

        $summary = [];
        foreach ($rows as $row) {
            $annee = (string) ($row['annee'] ?? 'Sans année');
            $summary[$annee] ??= ['annee' => $annee, 'entrees' => 0.0, 'sorties' => 0.0, 'solde' => 0.0];
            if ($row['type'] === MouvementCaisse::TYPE_ENTREE) {
                $summary[$annee]['entrees'] = (float) $row['total'];
            }
            if ($row['type'] === MouvementCaisse::TYPE_SORTIE) {
                $summary[$annee]['sorties'] = (float) $row['total'];
            }
            $summary[$annee]['solde'] = $summary[$annee]['entrees'] - $summary[$annee]['sorties'];
        }

        return array_values($summary);
    }

    private function sumByType(Ecole $ecole, string $type, ?AnneeScolaire $anneeScolaire): float
    {
        $qb = $this->createQueryBuilder('m')
            ->select('COALESCE(SUM(m.montant), 0)')
            ->andWhere('m.ecole = :ecole')
            ->andWhere('m.type = :type')
            ->setParameter('ecole', $ecole)
            ->setParameter('type', $type);

        if ($anneeScolaire instanceof AnneeScolaire) {
            $qb->andWhere('m.anneeScolaire = :annee')->setParameter('annee', $anneeScolaire);
        }

        return (float) ($qb
            ->getQuery()
            ->getSingleScalarResult() ?? 0);
    }
}
