<?php

namespace App\Command;

use App\Entity\Advert;
use App\Entity\PaymentReminder;
use App\Service\ActionService;
use App\Service\MailerService;
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 Twig\Environment;

#[AsCommand(
    name: 'app:payment:reminder',
    description: 'Envoie les relances de paiement aux clients selon l\'echeancier (15j, 10j, 5j, 3j, 1j, mise en demeure, resiliation)',
)]
class PaymentReminderCommand extends Command
{
    private const MONITOR_EMAIL = 'notification@e-cosplay.fr';

    public function __construct(
        private EntityManagerInterface $em,
        private MailerService $mailer,
        private Environment $twig,
        private LoggerInterface $logger,
        private ActionService $actionService,
    ) {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title('Relances de paiement');

        // Recupere tous les avis en etat "send" (envoyes, en attente de paiement)
        $adverts = $this->em->getRepository(Advert::class)->findBy(['state' => Advert::STATE_SEND]);

        if ([] === $adverts) {
            $io->success('Aucun avis de paiement en attente.');

            return Command::SUCCESS;
        }

        $now = new \DateTimeImmutable();
        $sent = 0;

        foreach ($adverts as $advert) {
            $customer = $advert->getCustomer();
            if (null === $customer || null === $customer->getEmail()) {
                continue;
            }

            $daysSinceSend = (int) $now->diff($advert->getUpdatedAt() ?? $advert->getCreatedAt())->days;
            $nextStep = $this->getNextStep($advert, $daysSinceSend);

            if (null === $nextStep) {
                continue;
            }

            $stepConfig = PaymentReminder::STEPS_CONFIG[$nextStep];
            $numOrder = $advert->getOrderNumber()->getNumOrder();

            $io->text(sprintf('  %s -> %s (%d j) -> %s', $numOrder, $customer->getEmail(), $daysSinceSend, $stepConfig['label']));

            try {
                // Execute l'action associee a l'etape
                $this->executeStep($advert, $nextStep, $customer);

                // Enregistre la relance
                $reminder = new PaymentReminder($advert, $nextStep, 'Jour '.$daysSinceSend.' - '.$stepConfig['label']);
                $this->em->persist($reminder);
                $this->em->flush();

                ++$sent;
            } catch (\Throwable $e) {
                $this->logger->error('PaymentReminder: erreur '.$numOrder.' step '.$nextStep.': '.$e->getMessage());
                $io->warning('Erreur '.$numOrder.' : '.$e->getMessage());
            }
        }

        $io->success($sent.' relance(s) envoyee(s) sur '.\count($adverts).' avis en attente.');

        return Command::SUCCESS;
    }

    /**
     * Determine la prochaine etape de relance non encore envoyee.
     */
    private function getNextStep(Advert $advert, int $daysSinceSend): ?string
    {
        $existingSteps = $this->em->getRepository(PaymentReminder::class)
            ->createQueryBuilder('r')
            ->select('r.step')
            ->where('r.advert = :advert')
            ->setParameter('advert', $advert)
            ->getQuery()
            ->getSingleColumnResult();

        foreach (PaymentReminder::STEPS_CONFIG as $step => $config) {
            if ($daysSinceSend >= $config['days'] && !\in_array($step, $existingSteps, true)) {
                return $step;
            }
        }

        return null;
    }

    private function executeStep(Advert $advert, string $step, mixed $customer): void
    {
        $numOrder = $advert->getOrderNumber()->getNumOrder();

        match ($step) {
            PaymentReminder::STEP_REMINDER_15 => $this->sendReminder($advert, $customer, 'Rappel de paiement', 'reminder'),
            PaymentReminder::STEP_WARNING_10 => $this->sendReminder($advert, $customer, 'Rappel + avertissement', 'warning'),
            PaymentReminder::STEP_SUSPENSION_WARNING_5 => $this->sendReminder($advert, $customer, 'Avertissement - Suspension des services imminente', 'suspension_warning'),
            PaymentReminder::STEP_FINAL_REMINDER_3 => $this->sendReminder($advert, $customer, 'Ultime rappel avant suspension', 'final_reminder'),
            PaymentReminder::STEP_SUSPENSION_1 => $this->handleSuspension($advert, $customer),
            PaymentReminder::STEP_FORMAL_NOTICE => $this->handleFormalNotice($advert, $customer),
            PaymentReminder::STEP_TERMINATION_WARNING => $this->handleTerminationWarning($advert, $customer),
            PaymentReminder::STEP_TERMINATION => $this->handleTermination($advert, $customer),
            // @codeCoverageIgnoreStart
            default => null,
            // @codeCoverageIgnoreEnd
        };

        // Notification admin pour chaque etape
        $this->mailer->sendEmail(
            self::MONITOR_EMAIL,
            'Relance '.$numOrder.' - '.PaymentReminder::STEPS_CONFIG[$step]['label'].' - '.$customer->getFullName(),
            $this->twig->render('emails/payment_reminder_admin.html.twig', [
                'customer' => $customer,
                'advert' => $advert,
                'step' => $step,
                'stepLabel' => PaymentReminder::STEPS_CONFIG[$step]['label'],
                'severity' => PaymentReminder::STEPS_CONFIG[$step]['severity'],
            ]),
            null,
            null,
            false,
        );
    }

    private function sendReminder(Advert $advert, mixed $customer, string $subject, string $type): void
    {
        $this->mailer->sendEmail(
            $customer->getEmail(),
            $subject.' - Avis '.$advert->getOrderNumber()->getNumOrder(),
            $this->twig->render('emails/payment_reminder_client.html.twig', [
                'customer' => $customer,
                'advert' => $advert,
                'type' => $type,
                'subject' => $subject,
            ]),
            null,
            null,
            false,
        );
    }

    private function handleSuspension(Advert $advert, mixed $customer): void
    {
        $this->sendReminder($advert, $customer, 'Suspension de vos services', 'suspension');

        // Suspension effective via ActionService (suspend client + sites + emails)
        $this->actionService->suspendCustomer($customer, 'Impaye avis '.$advert->getOrderNumber()->getNumOrder());
    }

    private function handleFormalNotice(Advert $advert, mixed $customer): void
    {
        $this->sendReminder($advert, $customer, 'Mise en demeure de paiement', 'formal_notice');
    }

    private function handleTerminationWarning(Advert $advert, mixed $customer): void
    {
        $this->sendReminder($advert, $customer, 'Avertissement - Resiliation du contrat et suppression de vos donnees', 'termination_warning');

        // Desactive le client definitivement
        $this->actionService->disableCustomer($customer, 'Pre-resiliation impaye avis '.$advert->getOrderNumber()->getNumOrder());
    }

    private function handleTermination(Advert $advert, mixed $customer): void
    {
        $this->sendReminder($advert, $customer, 'Resiliation de contrat et mise en recouvrement', 'termination');

        // Marque le client pour suppression (cron nocturne supprimera les donnees)
        $this->actionService->markForDeletion($customer, 'Resiliation + recouvrement avis '.$advert->getOrderNumber()->getNumOrder());

        // Annule l'avis
        $advert->setState(Advert::STATE_CANCEL);
        $this->em->flush();
    }
}
