<?php

namespace App\Command;

use App\Service\CloudflareService;
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:cloudflare:clean',
    description: 'Liste les zones Cloudflare et nettoie les enregistrements _acme-challenge obsoletes',
)]
class CloudflareDnsCleanCommand extends Command
{
    public function __construct(
        private CloudflareService $cloudflare,
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            ->addOption('zone', null, InputOption::VALUE_REQUIRED, 'Nettoyer uniquement cette zone (nom de domaine)')
            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Afficher les records a supprimer sans les supprimer')
            ->addOption('list-only', null, InputOption::VALUE_NONE, 'Lister uniquement les zones sans nettoyer');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title('Cloudflare DNS - Nettoyage des _acme-challenge');

        if (!$this->cloudflare->isAvailable()) {
            $io->error('API Cloudflare non disponible. Verifiez CLOUDFLARE_KEY.');

            return Command::FAILURE;
        }

        $zones = $this->cloudflare->listZones();

        if ([] === $zones) {
            $io->warning('Aucune zone trouvee.');
        } elseif ($input->getOption('list-only')) {
            $this->displayZones($io, $zones);
        } else {
            $this->displayZones($io, $zones);
            $filterZone = $input->getOption('zone');
            $dryRun = $input->getOption('dry-run');
            $totalDeleted = $this->cleanZones($io, $zones, $filterZone, $dryRun);

            $dryRun
                ? $io->success('Dry run termine. Aucun enregistrement supprime.')
                : $io->success($totalDeleted.' enregistrement(s) _acme-challenge supprime(s) au total.');
        }

        return Command::SUCCESS;
    }

    /** @param list<array<string, mixed>> $zones */
    private function displayZones(SymfonyStyle $io, array $zones): void
    {
        $io->section('Zones Cloudflare ('.\count($zones).')');
        $zoneTable = [];
        foreach ($zones as $zone) {
            $zoneTable[] = [$zone['name'], $zone['id'], $zone['status'], $zone['plan']['name'] ?? '?'];
        }
        $io->table(['Domaine', 'Zone ID', 'Statut', 'Plan'], $zoneTable);
    }

    /** @param list<array<string, mixed>> $zones */
    private function cleanZones(SymfonyStyle $io, array $zones, ?string $filterZone, bool $dryRun): int
    {
        $totalDeleted = 0;

        foreach ($zones as $zone) {
            if (null !== $filterZone && $zone['name'] !== $filterZone) {
                continue;
            }

            $totalDeleted += $this->cleanZone($io, $zone['name'], $zone['id'], $dryRun);
        }

        return $totalDeleted;
    }

    private function cleanZone(SymfonyStyle $io, string $zoneName, string $zoneId, bool $dryRun): int
    {
        $io->section($zoneName.' ('.$zoneId.')');

        $toDelete = array_filter(
            $this->cloudflare->getDnsRecordsByType($zoneId, 'TXT'),
            fn (array $r) => str_contains($r['name'] ?? '', '_acme-challenge'),
        );

        if ([] === $toDelete) {
            $io->text('  Aucun _acme-challenge trouve.');

            return 0;
        }

        $io->text('  '.\count($toDelete).' enregistrement(s) _acme-challenge trouve(s) :');
        foreach ($toDelete as $record) {
            $io->text('    - '.$record['name'].' => '.substr($record['content'] ?? '', 0, 50));
        }

        if ($dryRun) {
            $io->text('  [DRY RUN] Aucune suppression effectuee.');

            return 0;
        }

        return $this->deleteRecords($io, $zoneId, $toDelete);
    }

    /** @param list<array<string, mixed>> $records */
    private function deleteRecords(SymfonyStyle $io, string $zoneId, array $records): int
    {
        $deleted = 0;
        foreach ($records as $record) {
            if ($this->cloudflare->deleteDnsRecord($zoneId, $record['id'])) {
                ++$deleted;
            } else {
                $io->text('    <fg=red>ECHEC</> suppression de '.$record['name']);
            }
        }

        $io->text('  <fg=green>'.$deleted.'</> enregistrement(s) supprime(s).');

        return $deleted;
    }
}
