<?php

declare(strict_types=1);

namespace App\DataFixtures;

use App\Entity\AnneeScolaire;
use App\Entity\CategorieDepense;
use App\Entity\Ecole;
use App\Entity\RegleFrais;
use App\Entity\Section;
use App\Entity\TypeFrais;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;

final class FinanceFixtures extends Fixture implements DependentFixtureInterface
{
    public function load(ObjectManager $manager): void
    {
        $ecoleRepository = $manager->getRepository(Ecole::class);

        foreach ($this->typesFraisBySchool() as $slug => $types) {
            $ecole = $ecoleRepository->findOneBy(['slug' => $slug]);
            if (!$ecole instanceof Ecole) {
                continue;
            }

            $this->resetSchoolFees($manager, $ecole);

            $createdTypes = [];
            foreach ($types as $index => $data) {
                $type = $this->syncTypeFrais($manager, $ecole, $data + ['ordre' => $index + 1]);
                $createdTypes[$type->getCode()] = $type;
            }

            $annee = $this->activeYear($manager, $ecole);
            foreach ($this->reglesFraisBySchool($slug, $createdTypes, $annee, $manager, $ecole) as $index => $data) {
                $this->createRegleFrais($manager, $ecole, $data + ['ordre' => $index + 1]);
            }

            foreach ($this->categoriesDepense() as $index => $data) {
                $this->syncCategorieDepense($manager, $ecole, $data + ['ordre' => $index + 1]);
            }
        }

        $manager->flush();
    }

    public function getDependencies(): array
    {
        return [AcademicFixtures::class];
    }

    /**
     * @return array<string, list<array{code: string, libelle: string, nature: string, periodicite: string, montantDefaut: ?string, description: ?string}>>
     */
    private function typesFraisBySchool(): array
    {
        return [
            'qamar' => [
                ['code' => 'INSCRIPTION', 'libelle' => 'Inscription / réinscription', 'nature' => TypeFrais::NATURE_INSCRIPTION, 'periodicite' => TypeFrais::PERIODICITE_UNIQUE, 'montantDefaut' => '1000', 'description' => 'Frais d’inscription ou de réinscription Qamar.'],
                ['code' => 'ANNUEL', 'libelle' => 'Frais annuels', 'nature' => TypeFrais::NATURE_ANNUEL, 'periodicite' => TypeFrais::PERIODICITE_ANNUELLE, 'montantDefaut' => '10000', 'description' => 'Frais annuels de suivi pédagogique Qamar.'],
            ],
            'daroul-ilm' => [
                ['code' => 'INSCRIPTION_LIGNE', 'libelle' => 'Inscription cours en ligne', 'nature' => TypeFrais::NATURE_INSCRIPTION, 'periodicite' => TypeFrais::PERIODICITE_UNIQUE, 'montantDefaut' => '2000', 'description' => 'Frais d’inscription pour les cours en ligne WhatsApp.'],
                ['code' => 'MENSUALITE_LIGNE', 'libelle' => 'Mensualité cours en ligne', 'nature' => TypeFrais::NATURE_MENSUEL, 'periodicite' => TypeFrais::PERIODICITE_MENSUELLE, 'montantDefaut' => '2000', 'description' => 'Mensualité des cours en ligne WhatsApp.'],
                ['code' => 'DOCUMENT_PRESENTIEL', 'libelle' => 'Inscription + documents présentiel', 'nature' => TypeFrais::NATURE_DOCUMENT, 'periodicite' => TypeFrais::PERIODICITE_UNIQUE, 'montantDefaut' => '5000', 'description' => 'Frais d’inscription et documents pour le présentiel.'],
                ['code' => 'TARIF_PERSONNALISE', 'libelle' => 'Tarif personnalisé présentiel', 'nature' => TypeFrais::NATURE_PERSONNALISE, 'periodicite' => TypeFrais::PERIODICITE_PERSONNALISEE, 'montantDefaut' => null, 'description' => 'Tarif adapté selon le nombre de séances ou l’accord administratif.'],
            ],
            'sahaba' => [
                ['code' => 'ACOMPTE_INSCRIPTION', 'libelle' => 'Acompte à l’inscription', 'nature' => TypeFrais::NATURE_INSCRIPTION, 'periodicite' => TypeFrais::PERIODICITE_UNIQUE, 'montantDefaut' => '10000', 'description' => 'Montant payable à l’inscription.'],
                ['code' => 'SOLDE_ANNUEL', 'libelle' => 'Solde frais annuels', 'nature' => TypeFrais::NATURE_ANNUEL, 'periodicite' => TypeFrais::PERIODICITE_UNIQUE, 'montantDefaut' => '15000', 'description' => 'Solde des frais annuels à régler entre le 17 juillet 2026 et le 12 octobre 2026.'],
            ],
        ];
    }

    /**
     * @param array<string, TypeFrais> $types
     * @return list<array{typeFrais: TypeFrais, anneeScolaire: ?AnneeScolaire, section: ?Section, montant: string, periodicite: string, moisDebut: ?int, nombreEcheances: ?int, description: ?string}>
     */
    private function reglesFraisBySchool(string $slug, array $types, ?AnneeScolaire $annee, ObjectManager $manager, Ecole $ecole): array
    {
        if ($slug === 'qamar') {
            return [
                [
                    'typeFrais' => $types['INSCRIPTION'],
                    'anneeScolaire' => $annee,
                    'section' => null,
                    'montant' => '1000',
                    'periodicite' => TypeFrais::PERIODICITE_UNIQUE,
                    'moisDebut' => null,
                    'nombreEcheances' => null,
                    'description' => 'Frais unique d’inscription ou de réinscription Qamar.',
                ],
                [
                    'typeFrais' => $types['ANNUEL'],
                    'anneeScolaire' => $annee,
                    'section' => null,
                    'montant' => '10000',
                    'periodicite' => TypeFrais::PERIODICITE_ANNUELLE,
                    'moisDebut' => null,
                    'nombreEcheances' => null,
                    'description' => 'Frais annuels Qamar, valables pour tous les parcours.',
                ],
            ];
        }

        if ($slug === 'daroul-ilm') {
            $whatsapp = $this->section($manager, $ecole, 'cours-en-ligne-whatsapp');
            $presentiel = $this->section($manager, $ecole, 'presentiel-accompagnement-personnalise');
            $moisDebut = $annee?->getDateDebut() ? (int) $annee->getDateDebut()->format('m') : 5;

            return [
                [
                    'typeFrais' => $types['INSCRIPTION_LIGNE'],
                    'anneeScolaire' => $annee,
                    'section' => $whatsapp,
                    'montant' => '2000',
                    'periodicite' => TypeFrais::PERIODICITE_UNIQUE,
                    'moisDebut' => null,
                    'nombreEcheances' => null,
                    'description' => 'Inscription unique pour les cours en ligne WhatsApp.',
                ],
                [
                    'typeFrais' => $types['MENSUALITE_LIGNE'],
                    'anneeScolaire' => $annee,
                    'section' => $whatsapp,
                    'montant' => '2000',
                    'periodicite' => TypeFrais::PERIODICITE_MENSUELLE,
                    'moisDebut' => $moisDebut,
                    'nombreEcheances' => 12,
                    'description' => 'Mensualité des cours en ligne WhatsApp, générée sur douze mois.',
                ],
                [
                    'typeFrais' => $types['DOCUMENT_PRESENTIEL'],
                    'anneeScolaire' => $annee,
                    'section' => $presentiel,
                    'montant' => '5000',
                    'periodicite' => TypeFrais::PERIODICITE_UNIQUE,
                    'moisDebut' => null,
                    'nombreEcheances' => null,
                    'description' => 'Frais unique inscription + documents pour le présentiel.',
                ],
            ];
        }

        if ($slug === 'sahaba') {
            return [
                [
                    'typeFrais' => $types['ACOMPTE_INSCRIPTION'],
                    'anneeScolaire' => $annee,
                    'section' => null,
                    'montant' => '10000',
                    'periodicite' => TypeFrais::PERIODICITE_UNIQUE,
                    'moisDebut' => null,
                    'nombreEcheances' => null,
                    'description' => 'Acompte unique payable à l’inscription.',
                ],
                [
                    'typeFrais' => $types['SOLDE_ANNUEL'],
                    'anneeScolaire' => $annee,
                    'section' => null,
                    'montant' => '15000',
                    'periodicite' => TypeFrais::PERIODICITE_UNIQUE,
                    'moisDebut' => null,
                    'nombreEcheances' => null,
                    'description' => 'Solde des frais annuels. À régler entre le 17 juillet 2026 et le 12 octobre 2026.',
                ],
            ];
        }

        return [];
    }

    /**
     * @return list<array{code: string, libelle: string, description: ?string}>
     */
    private function categoriesDepense(): array
    {
        return [
            ['code' => 'ENSEIGNANT', 'libelle' => 'Paiement enseignants', 'description' => 'Paiements et primes des enseignants.'],
            ['code' => 'INTERNET', 'libelle' => 'Connexion internet', 'description' => 'Forfaits, connexion internet et outils en ligne.'],
            ['code' => 'FOURNITURES', 'libelle' => 'Fournitures', 'description' => 'Fournitures pédagogiques et administratives.'],
            ['code' => 'LOCATION', 'libelle' => 'Location', 'description' => 'Location de locaux ou salles.'],
            ['code' => 'TRANSPORT', 'libelle' => 'Transport', 'description' => 'Frais de déplacement et transport.'],
            ['code' => 'COMMUNICATION', 'libelle' => 'Communication', 'description' => 'Communication, téléphone, supports et annonces.'],
            ['code' => 'AUTRE', 'libelle' => 'Autres dépenses', 'description' => 'Autres sorties de caisse.'],
        ];
    }

    /**
     * @param array{code: string, libelle: string, nature: string, periodicite: string, montantDefaut: ?string, description: ?string, ordre: int} $data
     */
    private function syncTypeFrais(ObjectManager $manager, Ecole $ecole, array $data): TypeFrais
    {
        $type = $manager->getRepository(TypeFrais::class)->findOneBy(['ecole' => $ecole, 'code' => $data['code']]) ?? new TypeFrais();
        $type
            ->setEcole($ecole)
            ->setCode($data['code'])
            ->setLibelle($data['libelle'])
            ->setNature($data['nature'])
            ->setPeriodicite($data['periodicite'])
            ->setMontantDefaut($data['montantDefaut'])
            ->setDescription($data['description'])
            ->setOrdre($data['ordre'])
            ->setActif(true);

        $manager->persist($type);

        return $type;
    }

    /**
     * @param array{typeFrais: TypeFrais, anneeScolaire: ?AnneeScolaire, section: ?Section, montant: string, periodicite: string, moisDebut: ?int, nombreEcheances: ?int, description: ?string, ordre: int} $data
     */
    private function createRegleFrais(ObjectManager $manager, Ecole $ecole, array $data): RegleFrais
    {
        $regle = (new RegleFrais())
            ->setEcole($ecole)
            ->setTypeFrais($data['typeFrais'])
            ->setAnneeScolaire($data['anneeScolaire'])
            ->setSection($data['section'])
            ->setClasse(null)
            ->setMontant($data['montant'])
            ->setPeriodicite($data['periodicite'])
            ->setMoisDebut($data['moisDebut'])
            ->setNombreEcheances($data['nombreEcheances'])
            ->setDescription($data['description'])
            ->setActif(true);

        $manager->persist($regle);

        return $regle;
    }

    /**
     * @param array{code: string, libelle: string, description: ?string, ordre: int} $data
     */
    private function syncCategorieDepense(ObjectManager $manager, Ecole $ecole, array $data): CategorieDepense
    {
        $categorie = $manager->getRepository(CategorieDepense::class)->findOneBy(['ecole' => $ecole, 'code' => $data['code']]) ?? new CategorieDepense();
        $categorie
            ->setEcole($ecole)
            ->setCode($data['code'])
            ->setLibelle($data['libelle'])
            ->setDescription($data['description'])
            ->setOrdre($data['ordre'])
            ->setActif(true);

        $manager->persist($categorie);

        return $categorie;
    }

    private function resetSchoolFees(ObjectManager $manager, Ecole $ecole): void
    {
        foreach ($manager->getRepository(RegleFrais::class)->findBy(['ecole' => $ecole]) as $regle) {
            $manager->remove($regle);
        }
        $manager->flush();
    }

    private function activeYear(ObjectManager $manager, Ecole $ecole): ?AnneeScolaire
    {
        return $manager->getRepository(AnneeScolaire::class)->findOneBy(
            ['ecole' => $ecole, 'active' => true],
            ['dateDebut' => 'DESC', 'id' => 'DESC'],
        );
    }

    private function section(ObjectManager $manager, Ecole $ecole, string $slug): ?Section
    {
        return $manager->getRepository(Section::class)->findOneBy(['ecole' => $ecole, 'slug' => $slug]);
    }
}
