<?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\Cart\CartAbandonmentMarker;
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:cart:mark-abandoned',
    description: 'Marque les paniers inactifs non commandes et non payes comme abandonnes.'
)]
final class MarkAbandonedCartsCommand extends Command
{
    public function __construct(
        private readonly CartAbandonmentMarker $cartAbandonmentMarker,
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            ->addOption('pending-after-hours', null, InputOption::VALUE_REQUIRED, 'Delai d inactivite avant abandon pour un panier sans checkout.', '24')
            ->addOption('checkout-after-hours', null, InputOption::VALUE_REQUIRED, 'Delai d inactivite avant abandon pour un checkout initie sans retour paiement.', '2')
            ->addOption('limit', null, InputOption::VALUE_REQUIRED, 'Nombre maximal de paniers a marquer.', '100')
            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Affiche les paniers eligibles sans ecrire en base.');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $dryRun = (bool) $input->getOption('dry-run');
        $pendingAfterHours = $this->parsePositiveInteger($input->getOption('pending-after-hours'), 'pending-after-hours', $io);
        $checkoutAfterHours = $this->parsePositiveInteger($input->getOption('checkout-after-hours'), 'checkout-after-hours', $io);
        $limit = $this->parsePositiveInteger($input->getOption('limit'), 'limit', $io);

        if (null === $pendingAfterHours || null === $checkoutAfterHours || null === $limit) {
            return Command::INVALID;
        }

        $result = $this->cartAbandonmentMarker->mark(
            pendingAfterHours: $pendingAfterHours,
            checkoutAfterHours: $checkoutAfterHours,
            limit: $limit,
            dryRun: $dryRun,
        );

        $io->title('Marquage des paniers abandonnes');
        $io->definitionList(
            ['Dry run' => $dryRun ? 'oui' : 'non'],
            ['Panier sans checkout apres' => sprintf('%d h', $pendingAfterHours)],
            ['Checkout initie apres' => sprintf('%d h', $checkoutAfterHours)],
            ['Limite' => (string) $limit],
            ['Eligibles' => (string) \count($result->eligibleCarts)]
        );

        foreach ($result->eligibleCarts as $cart) {
            $io->writeln(sprintf(
                '%s - %s - derniere activite: %s',
                $cart->getId()->toString(),
                $cart->getCheckoutStatus(),
                $cart->getLastActivityAt()?->format('Y-m-d H:i:s') ?? '-'
            ));
        }

        $io->success(sprintf('%d panier(s) marque(s) abandonne(s).', $result->markedCount));

        return Command::SUCCESS;
    }

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

            return null;
        }

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

            return null;
        }

        return (int) $value;
    }
}
