<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Command;

use CpCreation\VitiCore\User\ExpiredRegistrationPurger;
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: 'viti-core:user:purge-expired-registrations',
    description: 'Supprime par lots les inscriptions non verifiees dont le lien d activation a expire.'
)]
final class PurgeExpiredRegistrationsCommand extends Command
{
    public function __construct(
        private readonly ExpiredRegistrationPurger $purger,
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            ->addOption(
                'batch-size',
                null,
                InputOption::VALUE_REQUIRED,
                'Nombre maximal d inscriptions traitees par lot.',
                (string) ExpiredRegistrationPurger::DEFAULT_BATCH_SIZE,
            )
            ->addOption(
                'max-batches',
                null,
                InputOption::VALUE_REQUIRED,
                'Nombre maximal de lots traites pendant une execution.',
                (string) ExpiredRegistrationPurger::DEFAULT_MAX_BATCHES,
            )
            ->addOption(
                'dry-run',
                null,
                InputOption::VALUE_NONE,
                'Compte les inscriptions eligibles sans supprimer de donnees.',
            )
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $batchSize = $this->parseBoundedPositiveInteger(
            $input->getOption('batch-size'),
            'batch-size',
            ExpiredRegistrationPurger::MAX_BATCH_SIZE,
            $io,
        );
        $maxBatches = $this->parseBoundedPositiveInteger(
            $input->getOption('max-batches'),
            'max-batches',
            ExpiredRegistrationPurger::MAX_BATCHES,
            $io,
        );

        if (null === $batchSize || null === $maxBatches) {
            return Command::INVALID;
        }

        $dryRun = (bool) $input->getOption('dry-run');
        $result = $this->purger->purge(
            batchSize: $batchSize,
            maxBatches: $maxBatches,
            dryRun: $dryRun,
        );

        $io->title('Purge des inscriptions expirees');
        $io->definitionList(
            ['Simulation' => $dryRun ? 'oui' : 'non'],
            ['Taille des lots' => (string) $batchSize],
            ['Nombre maximal de lots' => (string) $maxBatches],
            ['Delai de grace apres expiration' => sprintf('%d jours', ExpiredRegistrationPurger::EXPIRATION_GRACE_DAYS)],
            ['Inscriptions eligibles' => (string) $result->eligibleCount],
            ['Comptes supprimes' => (string) $result->deletedCount],
            ['Inscriptions ignorees apres verification' => (string) $result->skippedCount],
            ['Logs techniques supprimes' => (string) $result->emailLogsDeleted],
            ['Entrees d audit supprimees' => (string) $result->auditRowsDeleted],
            ['Lots traites' => (string) $result->batchCount],
            ['Reste a traiter' => $result->hasMore ? 'oui' : 'non'],
        );

        if ($dryRun) {
            $io->success("Simulation terminee. Aucune donnee n'a ete supprimee.");
        } else {
            $io->success(sprintf('%d inscription(s) expiree(s) supprimee(s).', $result->deletedCount));
        }

        if ($result->hasMore) {
            $io->warning('La limite de cette execution est atteinte. Une nouvelle execution est necessaire.');
        }

        return Command::SUCCESS;
    }

    private function parseBoundedPositiveInteger(
        mixed $value,
        string $option,
        int $maximum,
        SymfonyStyle $io,
    ): ?int {
        if (!\is_scalar($value) && !$value instanceof \Stringable) {
            $io->error(sprintf('L option --%s doit etre un entier compris entre 1 et %d.', $option, $maximum));

            return null;
        }

        $value = (string) $value;
        if (!ctype_digit($value) || (int) $value < 1 || (int) $value > $maximum) {
            $io->error(sprintf('L option --%s doit etre un entier compris entre 1 et %d.', $option, $maximum));

            return null;
        }

        return (int) $value;
    }
}
