<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Console;

use App\Administration\Domain\Repository\ParentInvitationRepository;
use App\Shared\Domain\Clock;

use function count;

use Override;
use Psr\Log\LoggerInterface;

use function sprintf;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;

/**
 * Marque comme expirées les invitations parents envoyées dont la date d'expiration est dépassée.
 *
 * CRON: 0 6 * * * php bin/console app:expire-parent-invitations
 */
#[AsCommand(
    name: 'app:expire-parent-invitations',
    description: 'Marque comme expirées les invitations parents dont la date limite est dépassée',
)]
final class ExpireInvitationsCommand extends Command
{
    public function __construct(
        private readonly ParentInvitationRepository $invitationRepository,
        private readonly Clock $clock,
        private readonly LoggerInterface $logger,
    ) {
        parent::__construct();
    }

    #[Override]
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title('Expiration des invitations parents');

        $now = $this->clock->now();
        $expiredInvitations = $this->invitationRepository->findExpiredSent($now);

        if ($expiredInvitations === []) {
            $io->success('Aucune invitation expirée à traiter.');

            return Command::SUCCESS;
        }

        $io->info(sprintf('%d invitation(s) expirée(s) trouvée(s)', count($expiredInvitations)));

        $expiredCount = 0;

        foreach ($expiredInvitations as $invitation) {
            try {
                $invitation->marquerExpiree();
                $this->invitationRepository->save($invitation);

                $this->logger->info('Invitation parent marquée expirée', [
                    'invitation_id' => (string) $invitation->id,
                    'tenant_id' => (string) $invitation->tenantId,
                    'parent_email' => (string) $invitation->parentEmail,
                ]);

                ++$expiredCount;
            } catch (Throwable $e) {
                $io->error(sprintf(
                    'Erreur pour l\'invitation %s : %s',
                    $invitation->id,
                    $e->getMessage(),
                ));

                $this->logger->error('Erreur lors de l\'expiration de l\'invitation', [
                    'invitation_id' => (string) $invitation->id,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        $io->success(sprintf('%d invitation(s) marquée(s) comme expirée(s).', $expiredCount));

        return Command::SUCCESS;
    }
}
