<?php

namespace App\Command;

use App\Entity\Echeancier;
use App\Entity\EcheancierLine;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
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:echeancier:process-payments',
    description: 'Traite les echeances dues : cree un PaymentIntent Stripe pour chaque ligne a prelever.',
)]
class EcheancierProcessPaymentsCommand extends Command
{
    public function __construct(
        private EntityManagerInterface $em,
        private LoggerInterface $logger,
        #[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;
        }

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

        $today = new \DateTimeImmutable('today');

        $lines = $this->em->createQuery(
            'SELECT l FROM App\Entity\EcheancierLine l
             JOIN l.echeancier e
             WHERE l.state = :state
             AND l.scheduledAt <= :today
             AND l.stripePaymentIntentId IS NULL
             AND e.state = :activeState
             AND e.stripePaymentMethodId IS NOT NULL
             AND e.stripeCustomerId IS NOT NULL
             ORDER BY l.scheduledAt ASC'
        )
            ->setParameter('state', EcheancierLine::STATE_PREPARED)
            ->setParameter('today', $today)
            ->setParameter('activeState', Echeancier::STATE_ACTIVE)
            ->getResult();

        $created = 0;
        $errors = 0;

        /** @var EcheancierLine $line */
        foreach ($lines as $line) {
            $echeancier = $line->getEcheancier();

            try {
                $pi = \Stripe\PaymentIntent::create([
                    'amount' => (int) round((float) $line->getAmount() * 100),
                    'currency' => 'eur',
                    'customer' => $echeancier->getStripeCustomerId(),
                    'payment_method' => $echeancier->getStripePaymentMethodId(),
                    'off_session' => true,
                    'confirm' => true,
                    'payment_method_types' => ['sepa_debit'],
                    'metadata' => [
                        'echeancier_id' => (string) $echeancier->getId(),
                        'echeancier_line_id' => (string) $line->getId(),
                        'position' => (string) $line->getPosition(),
                        'reference' => $echeancier->getReference(),
                    ],
                    'description' => $line->getLabel().' - '.$echeancier->getReference(),
                ]);

                $line->setStripePaymentIntentId($pi->id);
                $this->em->flush();

                ++$created;
                $this->logger->info('Echeancier cron: PI cree pour '.$echeancier->getReference().' echeance '.$line->getPosition(), [
                    'pi_id' => $pi->id,
                    'amount' => $line->getAmount(),
                ]);
            } catch (\Throwable $e) {
                ++$errors;
                $this->logger->error('Echeancier cron: erreur PI pour '.$echeancier->getReference().' echeance '.$line->getPosition().': '.$e->getMessage());

                $io->warning($echeancier->getReference().' echeance '.$line->getPosition().': '.$e->getMessage());
            }
        }

        // E-Flex : meme logique
        $eflexLines = $this->em->createQuery(
            'SELECT l FROM App\Entity\EFlexLine l
             JOIN l.eflex e
             WHERE l.state = :state
             AND l.scheduledAt <= :today
             AND l.stripePaymentIntentId IS NULL
             AND e.state = :activeState
             AND e.stripePaymentMethodId IS NOT NULL
             AND e.stripeCustomerId IS NOT NULL
             AND e.paymentMethod = :sepa
             ORDER BY l.scheduledAt ASC'
        )
            ->setParameter('state', \App\Entity\EFlexLine::STATE_PREPARED)
            ->setParameter('today', $today)
            ->setParameter('activeState', \App\Entity\EFlex::STATE_ACTIVE)
            ->setParameter('sepa', \App\Entity\EFlex::METHOD_SEPA)
            ->getResult();

        /** @var \App\Entity\EFlexLine $line */
        foreach ($eflexLines as $line) {
            $eflex = $line->getEflex();

            try {
                $pi = \Stripe\PaymentIntent::create([
                    'amount' => (int) round((float) $line->getAmount() * 100),
                    'currency' => 'eur',
                    'customer' => $eflex->getStripeCustomerId(),
                    'payment_method' => $eflex->getStripePaymentMethodId(),
                    'off_session' => true,
                    'confirm' => true,
                    'payment_method_types' => ['sepa_debit'],
                    'metadata' => [
                        'eflex_id' => (string) $eflex->getId(),
                        'eflex_line_id' => (string) $line->getId(),
                        'position' => (string) $line->getPosition(),
                        'reference' => $eflex->getReference(),
                    ],
                    'description' => $line->getLabel().' - '.$eflex->getReference(),
                ]);

                $line->setStripePaymentIntentId($pi->id);
                $this->em->flush();

                ++$created;
            } catch (\Throwable $e) {
                ++$errors;
                $io->warning($eflex->getReference().' echeance '.$line->getPosition().': '.$e->getMessage());
            }
        }

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

        return Command::SUCCESS;
    }
}
