<?php
declare(strict_types=1);

namespace App\Commands;

use App\Entity\Galaxy;
use App\Services\GalaxyFactory;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Console\Question\ConfirmationQuestion;

#[AsCommand(
    name: 'astra:delete:galaxy',
    description: 'Supprime une ou plusieurs galaxies et toutes leurs entités associées'
)]
class DeleteGalaxyCommand extends Command
{
    public function __construct(
        private EntityManagerInterface $entityManager,
        private GalaxyFactory $galaxyFactory
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            ->addArgument(
                'galaxy-ids',
                InputArgument::IS_ARRAY | InputArgument::OPTIONAL,
                'IDs des galaxies à supprimer (séparés par des espaces)'
            )
            ->addOption(
                'all',
                'a',
                InputOption::VALUE_NONE,
                'Supprimer toutes les galaxies'
            )
            ->addOption(
                'force',
                'f',
                InputOption::VALUE_NONE,
                'Forcer la suppression sans demander confirmation'
            )
            ->addOption(
                'dry-run',
                'd',
                InputOption::VALUE_NONE,
                'Afficher ce qui serait supprimé sans effectuer la suppression'
            )
            ->setHelp(
                <<<EOT
Cette commande permet de supprimer des galaxies et toutes leurs entités associées.

Exemples d'utilisation :
  <info>php bin/console astra:delete:galaxy 1</info>              # Supprime la galaxie avec l'ID 1
  <info>php bin/console astra:delete:galaxy 1 2 3</info>          # Supprime les galaxies 1, 2 et 3
  <info>php bin/console astra:delete:galaxy --all</info>          # Supprime toutes les galaxies
  <info>php bin/console astra:delete:galaxy --all --force</info>  # Supprime toutes les galaxies sans confirmation
  <info>php bin/console astra:delete:galaxy 1 --dry-run</info>    # Affiche ce qui serait supprimé sans supprimer

<comment>ATTENTION :</comment> Cette opération est <error>irréversible</error> et supprimera définitivement :
- La/les galaxie(s) spécifiée(s)
- Tous les secteurs associés
- Tous les systèmes stellaires
- Toutes les planètes
- Les relations avec les jeux (le jeu sera conservé mais détaché)
EOT
            );
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $galaxyIds = $input->getArgument('galaxy-ids');
        $deleteAll = $input->getOption('all');
        $force = $input->getOption('force');
        $dryRun = $input->getOption('dry-run');

        if (!$deleteAll && empty($galaxyIds)) {
            $io->error('Vous devez spécifier au moins un ID de galaxie ou utiliser --all pour supprimer toutes les galaxies.');
            return Command::FAILURE;
        }

        if ($deleteAll && !empty($galaxyIds)) {
            $io->error('Vous ne pouvez pas utiliser --all et spécifier des IDs en même temps.');
            return Command::FAILURE;
        }

        // Récupérer les galaxies à supprimer
        $galaxies = $this->getGalaxiesToDelete($galaxyIds, $deleteAll, $io);

        if (empty($galaxies)) {
            $io->warning('Aucune galaxie à supprimer.');
            return Command::SUCCESS;
        }

        // Afficher les informations sur ce qui va être supprimé
        $this->displayDeletionPreview($io, $galaxies, $dryRun);

        if ($dryRun) {
            $io->note('Mode dry-run activé : aucune suppression effectuée.');
            return Command::SUCCESS;
        }

        // Demander confirmation si pas forcé
        if (!$force && !$this->confirmDeletion($io, $galaxies)) {
            $io->info('Suppression annulée.');
            return Command::SUCCESS;
        }

        // Effectuer la suppression
        return $this->performDeletion($io, $galaxies, $deleteAll);
    }

    private function getGalaxiesToDelete(array $galaxyIds, bool $deleteAll, SymfonyStyle $io): array
    {
        $galaxyRepository = $this->entityManager->getRepository(Galaxy::class);

        if ($deleteAll) {
            return $galaxyRepository->findAll();
        }

        $galaxies = [];
        $notFoundIds = [];

        foreach ($galaxyIds as $id) {
            $galaxy = $galaxyRepository->find($id);
            if ($galaxy) {
                $galaxies[] = $galaxy;
            } else {
                $notFoundIds[] = $id;
            }
        }

        if (!empty($notFoundIds)) {
            $io->warning('Galaxies non trouvées avec les IDs : ' . implode(', ', $notFoundIds));
        }

        return $galaxies;
    }

    private function displayDeletionPreview(SymfonyStyle $io, array $galaxies, bool $dryRun): void
    {
        $title = $dryRun ? 'Aperçu de la suppression (dry-run)' : 'Galaxies à supprimer';
        $io->title($title);

        $totalStats = [
            'galaxies' => 0,
            'sectors' => 0,
            'systems' => 0,
            'planets' => 0,
            'habitablePlanets' => 0,
            'terraformablePlanets' => 0,
            'gamesDetached' => 0
        ];

        $tableData = [];

        foreach ($galaxies as $galaxy) {
            $counts = $this->galaxyFactory->countGalaxyEntities($galaxy);
            $totalStats['galaxies']++;
            $totalStats['sectors'] += $counts['sectors'];
            $totalStats['systems'] += $counts['systems'];
            $totalStats['planets'] += $counts['planets'];
            $totalStats['habitablePlanets'] += $counts['habitablePlanets'];
            $totalStats['terraformablePlanets'] += $counts['terraformablePlanets'];

            if ($galaxy->getGame()) {
                $totalStats['gamesDetached']++;
            }

            $tableData[] = [
                $galaxy->getId(),
                $galaxy->getName(),
                $counts['sectors'],
                $counts['systems'],
                $counts['planets'],
                $counts['habitablePlanets'],
                $counts['terraformablePlanets'],
                $galaxy->getGame() ? 'Oui' : 'Non'
            ];
        }

        $io->table(
            ['ID', 'Nom', 'Secteurs', 'Systèmes', 'Planètes', 'Habitables', 'Terraformables', 'Jeu associé'],
            $tableData
        );

        $io->section('Résumé total');
        $io->definitionList(
            ['Galaxies' => $totalStats['galaxies']],
            ['Secteurs' => $totalStats['sectors']],
            ['Systèmes stellaires' => $totalStats['systems']],
            ['Planètes' => $totalStats['planets']],
            ['Planètes habitables' => $totalStats['habitablePlanets']],
            ['Planètes terraformables' => $totalStats['terraformablePlanets']],
            ['Jeux détachés' => $totalStats['gamesDetached']]
        );
    }

    private function confirmDeletion(SymfonyStyle $io, array $galaxies): bool
    {
        $count = count($galaxies);
        $message = $count === 1
            ? "Êtes-vous sûr de vouloir supprimer cette galaxie ? Cette action est irréversible."
            : "Êtes-vous sûr de vouloir supprimer ces {$count} galaxies ? Cette action est irréversible.";

        $question = new ConfirmationQuestion($message, false);
        return $io->askQuestion($question);
    }

    private function performDeletion(SymfonyStyle $io, array $galaxies, bool $deleteAll): int
    {
        $io->section('Suppression en cours...');

        $progressBar = $io->createProgressBar(count($galaxies));
        $progressBar->start();

        $allStats = [];
        $errors = [];

        foreach ($galaxies as $galaxy) {
            try {
                $stats = $this->deleteGalaxy($galaxy);
                $allStats[] = $stats;
                $progressBar->advance();
            } catch (\Exception $e) {
                $errors[] = [
                    'galaxy' => $galaxy->getName() . ' (ID: ' . $galaxy->getId() . ')',
                    'error' => $e->getMessage()
                ];
                $progressBar->advance();
            }
        }

        $progressBar->finish();
        $io->newLine(2);

        // Afficher les résultats
        $this->displayDeletionResults($io, $allStats, $errors);

        return empty($errors) ? Command::SUCCESS : Command::FAILURE;
    }

    private function displayDeletionResults(SymfonyStyle $io, array $allStats, array $errors): void
    {
        if (!empty($allStats)) {
            $io->success('Suppression terminée avec succès !');

            $totalDeleted = [
                'galaxies' => count($allStats),
                'sectors' => array_sum(array_column($allStats, 'sectorsDeleted')),
                'systems' => array_sum(array_column($allStats, 'systemsDeleted')),
                'planets' => array_sum(array_column($allStats, 'planetsDeleted')),
                'gamesDetached' => count(array_filter($allStats, fn($s) => $s['gameDetached']))
            ];

            $io->definitionList(
                ['Galaxies supprimées' => $totalDeleted['galaxies']],
                ['Secteurs supprimés' => $totalDeleted['sectors']],
                ['Systèmes supprimés' => $totalDeleted['systems']],
                ['Planètes supprimées' => $totalDeleted['planets']],
                ['Jeux détachés' => $totalDeleted['gamesDetached']]
            );

            // Détail par galaxie
            if (count($allStats) > 1) {
                $io->section('Détail par galaxie');
                $tableData = [];
                foreach ($allStats as $stats) {
                    if (!isset($stats['error'])) {
                        $tableData[] = [
                            $stats['galaxyId'],
                            $stats['galaxyName'],
                            $stats['sectorsDeleted'],
                            $stats['systemsDeleted'],
                            $stats['planetsDeleted']
                        ];
                    }
                }
                $io->table(['ID', 'Nom', 'Secteurs', 'Systèmes', 'Planètes'], $tableData);
            }
        }

        if (!empty($errors)) {
            $io->error('Certaines suppressions ont échoué :');
            foreach ($errors as $error) {
                $io->text("• {$error['galaxy']} : {$error['error']}");
            }
        }
    }

    /**
     * Supprime une galaxie et toutes ses entités associées
     */
    public function deleteGalaxy(Galaxy $galaxy): array
    {
        $stats = [
            'galaxyName' => $galaxy->getName(),
            'galaxyId' => $galaxy->getId(),
            'sectorsDeleted' => 0,
            'systemsDeleted' => 0,
            'planetsDeleted' => 0,
            'gameDetached' => false
        ];

        // Détacher le jeu associé s'il existe
        if ($galaxy->getGame()) {
            $galaxy->getGame()->setGalaxy(null);
            $stats['gameDetached'] = true;
        }

        // Compter les entités avant suppression
        foreach ($galaxy->getSectors() as $sector) {
            $stats['sectorsDeleted']++;

            foreach ($sector->getSystems() as $system) {
                $stats['systemsDeleted']++;
                $stats['planetsDeleted'] += $system->getPlanets()->count();
            }
        }

        // Supprimer la galaxie (cascade supprimera automatiquement les secteurs, systèmes et planètes)
        $this->entityManager->remove($galaxy);
        $this->entityManager->flush();

        return $stats;
    }
}