<?php

namespace App\Command;

use App\Entity\Advert;
use App\Entity\AdvertPayment;
use App\Entity\CustomerPaymentMethod;
use App\Service\MailerService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Twig\Environment;
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 Symfony\Component\DependencyInjection\Attribute\Autowire;

#[AsCommand(
    name: 'app:advert:auto-payment',
    description: 'Preleve automatiquement les avis de paiement envoyes pour les clients avec prelevement auto configure.',
)]
class AdvertAutoPaymentCommand extends Command
{
    public function __construct(
        private EntityManagerInterface $em,
        private LoggerInterface $logger,
        private MailerService $mailer,
        private Environment $twig,
        #[Autowire(env: 'STRIPE_SK')] private string $stripeSk,
    ) {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        if ('' === $this->stripeSk) {
            $io->error('STRIPE_SK non configure.');

            return Command::FAILURE;
        }

        // Verifier si c'est le dernier jour du mois
        $today = new \DateTimeImmutable('today');
        $lastDay = new \DateTimeImmutable($today->format('Y-m-t'));

        if ($today->format('Y-m-d') !== $lastDay->format('Y-m-d')) {
            $io->info('Pas le dernier jour du mois ('.$today->format('d/m/Y').'). Rien a faire.');

            return Command::SUCCESS;
        }

        \Stripe\Stripe::setApiKey($this->stripeSk);

        // Trouver tous les avis envoyes (state = send)
        $adverts = $this->em->createQuery(
            'SELECT a FROM App\Entity\Advert a
             WHERE a.state = :state
             ORDER BY a.createdAt ASC'
        )
            ->setParameter('state', Advert::STATE_SEND)
            ->getResult();

        $created = 0;
        $skipped = 0;
        $errors = 0;

        /** @var Advert $advert */
        foreach ($adverts as $advert) {
            $customer = $advert->getCustomer();
            if (null === $customer) {
                ++$skipped;

                continue;
            }

            // Chercher le moyen de paiement par defaut du client
            $defaultPm = $this->em->getRepository(CustomerPaymentMethod::class)->findOneBy([
                'customer' => $customer,
                'isDefault' => true,
            ]);

            if (null === $defaultPm) {
                ++$skipped;

                continue;
            }

            $stripeCustomerId = $customer->getStripeCustomerId();
            if (null === $stripeCustomerId) {
                ++$skipped;

                continue;
            }

            // Calculer le montant restant a payer
            $totalTtc = (float) $advert->getTotalTtc();
            $totalPaid = 0.0;
            foreach ($advert->getPayments() as $payment) {
                if (AdvertPayment::TYPE_SUCCESS === $payment->getType()) {
                    $totalPaid += (float) $payment->getAmount();
                }
            }

            $remaining = $totalTtc - $totalPaid;
            if ($remaining <= 0) {
                ++$skipped;

                continue;
            }

            $amountCents = (int) round($remaining * 100);

            // Envoyer un mail d'annonce de prelevement
            if (null !== $customer->getEmail()) {
                try {
                    $this->mailer->sendEmail(
                        $customer->getEmail(),
                        'Prelevement automatique - Avis '.$advert->getOrderNumber()->getNumOrder(),
                        $this->twig->render('emails/advert_auto_payment_notice.html.twig', [
                            'customer' => $customer,
                            'advert' => $advert,
                            'amount' => $remaining,
                            'methodLabel' => $defaultPm->getDisplayLabel(),
                        ]),
                        null,
                        null,
                        false,
                    );
                } catch (\Throwable) {
                    // silencieux
                }
            }

            try {
                $pi = \Stripe\PaymentIntent::create([
                    'amount' => $amountCents,
                    'currency' => 'eur',
                    'customer' => $stripeCustomerId,
                    'payment_method' => $defaultPm->getStripePaymentMethodId(),
                    'off_session' => true,
                    'confirm' => true,
                    'payment_method_types' => [$defaultPm->getType()],
                    'metadata' => [
                        'advert_id' => (string) $advert->getId(),
                        'auto_payment' => '1',
                        'payment_method' => $defaultPm->getType(),
                    ],
                    'description' => 'Avis '.$advert->getOrderNumber()->getNumOrder().' - Prelevement auto',
                ]);

                ++$created;
                $this->logger->info('Auto-payment: PI cree pour avis '.$advert->getOrderNumber()->getNumOrder(), [
                    'pi_id' => $pi->id,
                    'amount' => number_format($remaining, 2),
                    'method' => $defaultPm->getTypeLabel(),
                ]);
            } catch (\Throwable $e) {
                ++$errors;
                $this->logger->error('Auto-payment: erreur pour avis '.$advert->getOrderNumber()->getNumOrder().': '.$e->getMessage());
                $io->warning($advert->getOrderNumber()->getNumOrder().': '.$e->getMessage());
            }
        }

        $io->success($created.' prelevement(s) lance(s), '.$skipped.' ignore(s), '.$errors.' erreur(s).');

        return Command::SUCCESS;
    }
}
