<?php

declare(strict_types=1);

namespace App\Command;

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\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

#[AsCommand(
    name: 'app:finance:seed',
    description: 'Crée ou met à jour les types de frais, règles de frais et catégories de dépenses des madrassas pilotes.',
)]
final class SeedFinanceCommand extends Command
{
    public function __construct(private readonly EntityManagerInterface $entityManager)
    {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            ->addOption('school', null, InputOption::VALUE_REQUIRED, 'Slug école à traiter : qamar, daroul-ilm, sahaba ou all.', 'all')
            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Teste la commande sans écrire définitivement en base.');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $schoolOption = (string) $input->getOption('school');
        $dryRun = (bool) $input->getOption('dry-run');
        $slugs = $schoolOption === 'all' ? array_keys($this->typesFraisBySchool()) : [$schoolOption];

        $unknown = array_diff($slugs, array_keys($this->typesFraisBySchool()));
        if ($unknown !== []) {
            $io->error('École inconnue : '.implode(', ', $unknown).'. Valeurs possibles : qamar, daroul-ilm, sahaba, all.');

            return Command::FAILURE;
        }

        $connection = $this->entityManager->getConnection();
        $connection->beginTransaction();

        try {
            foreach ($slugs as $slug) {
                $ecole = $this->entityManager->getRepository(Ecole::class)->findOneBy(['slug' => $slug]);
                if (!$ecole instanceof Ecole) {
                    $io->warning(sprintf('École "%s" introuvable, ignorée.', $slug));
                    continue;
                }

                $io->section($ecole->getNom() ?: $slug);
                $this->resetRules($ecole);

                $createdTypes = [];
                foreach ($this->typesFraisBySchool()[$slug] as $index => $data) {
                    $type = $this->syncTypeFrais($ecole, $data + ['ordre' => $index + 1]);
                    $createdTypes[$type->getCode()] = $type;
                    $io->writeln(sprintf('Type de frais : %s', $type->getCode()));
                }

                $annee = $this->activeYear($ecole);
                foreach ($this->reglesFraisBySchool($slug, $createdTypes, $annee, $ecole) as $data) {
                    $regle = $this->createRegleFrais($ecole, $data);
                    $io->writeln(sprintf(
                        'Règle : %s - %s FCFA',
                        $regle->getTypeFrais()?->getLibelle() ?: '-',
                        $regle->getMontant() ?: '0'
                    ));
                }

                foreach ($this->categoriesDepense() as $index => $data) {
                    $categorie = $this->syncCategorieDepense($ecole, $data + ['ordre' => $index + 1]);
                    $io->writeln(sprintf('Catégorie dépense : %s', $categorie->getCode()));
                }
            }

            $this->entityManager->flush();

            if ($dryRun) {
                $connection->rollBack();
                $io->success('Simulation terminée : aucune donnée n’a été enregistrée.');

                return Command::SUCCESS;
            }

            $connection->commit();
            $io->success('Données finance synchronisées.');

            return Command::SUCCESS;
        } catch (\Throwable $exception) {
            $connection->rollBack();
            $io->error($exception->getMessage());

            return Command::FAILURE;
        }
    }

    /** @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 */
    private function reglesFraisBySchool(string $slug, array $types, ?AnneeScolaire $annee, 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($ecole, 'cours-en-ligne-whatsapp');
            $presentiel = $this->section($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 [];
    }

    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.'],
        ];
    }

    private function resetRules(Ecole $ecole): void
    {
        foreach ($this->entityManager->getRepository(RegleFrais::class)->findBy(['ecole' => $ecole]) as $regle) {
            $this->entityManager->remove($regle);
        }
        $this->entityManager->flush();
    }

    private function syncTypeFrais(Ecole $ecole, array $data): TypeFrais
    {
        $type = $this->entityManager->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);

        $this->entityManager->persist($type);

        return $type;
    }

    private function createRegleFrais(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);

        $this->entityManager->persist($regle);

        return $regle;
    }

    private function syncCategorieDepense(Ecole $ecole, array $data): CategorieDepense
    {
        $categorie = $this->entityManager->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);

        $this->entityManager->persist($categorie);

        return $categorie;
    }

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

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