<?php

namespace App\Service;

use App\Entity\BilletBuyer;
use App\Entity\BilletDesign;
use App\Entity\BilletOrder;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\EntityManagerInterface;
use Dompdf\Dompdf;
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\Writer\PngWriter;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Twig\Environment;

/**
 * @codeCoverageIgnore PDF generation + email sending
 */
class BilletOrderService
{
    public function __construct(
        private EntityManagerInterface $em,
        private Environment $twig,
        private MailerService $mailer,
        private InvoiceService $invoiceService,
        private OrderIndexService $orderIndex,
        private UrlGeneratorInterface $urlGenerator,
        #[Autowire('%kernel.project_dir%')] private string $projectDir,
        #[Autowire('%kernel.secret%')] private string $appSecret,
    ) {
    }

    public function generateOrderTickets(BilletBuyer $order): void
    {
        $this->em->wrapInTransaction(function () use ($order): void {
            foreach ($order->getItems() as $item) {
                $billet = $item->getBillet();
                if (!$billet) {
                    continue;
                }

                if (null !== $billet->getQuantity()) {
                    $this->em->refresh($billet, LockMode::PESSIMISTIC_WRITE);
                    $newQty = $billet->getQuantity() - $item->getQuantity();
                    $billet->setQuantity(max(0, $newQty));
                }

                if (!\in_array($billet->getType(), ['billet', 'staff', 'exposant'], true) || !$billet->isGeneratedBillet()) {
                    continue;
                }

                for ($i = 0; $i < $item->getQuantity(); ++$i) {
                    $ticket = new BilletOrder();
                    $ticket->setBilletBuyer($order);
                    $ticket->setBillet($billet);
                    $ticket->setBilletName($item->getBilletName());
                    $ticket->setUnitPriceHT($item->getUnitPriceHT());
                    $ticket->setSecurityKey(BilletOrder::generateSecurityKey($ticket->getReference(), $this->appSecret));

                    $this->em->persist($ticket);
                }
            }

            $order->setStatus(BilletBuyer::STATUS_PAID);
            $order->setPaidAt(new \DateTimeImmutable());
        });

        $this->orderIndex->indexOrder($order);
    }

    public function notifyOrganizerCancelled(BilletBuyer $order, string $action = 'annulee'): void
    {
        $organizer = $order->getEvent()->getAccount();
        if (!$organizer || !$organizer->getEmail()) {
            return;
        }

        $html = $this->twig->render('email/order_cancelled_orga.html.twig', [
            'order' => $order,
            'action' => $action,
        ]);

        $this->mailer->sendEmail(
            $organizer->getEmail(),
            'Commande '.$action.' - '.$order->getEvent()->getTitle(),
            $html,
        );
    }

    public function generatePdf(BilletOrder $ticket): string
    {
        $order = $ticket->getBilletBuyer();
        $event = $order->getEvent();
        $organizer = $event->getAccount();

        $design = $this->em->getRepository(BilletDesign::class)->findOneBy(['event' => $event]);

        $eventUrl = $this->urlGenerator->generate('app_event_detail', [
            'orgaSlug' => $organizer->getSlug(),
            'id' => $event->getId(),
            'eventSlug' => $event->getSlug(),
        ], UrlGeneratorInterface::ABSOLUTE_URL);

        $ticketQrData = base64_encode($ticket->getReference());
        $ticketQrCode = (new Builder(
            writer: new PngWriter(),
            data: $ticketQrData,
            encoding: new Encoding('UTF-8'),
            size: 200,
            margin: 5,
        ))->build();
        $qrBase64 = 'data:image/png;base64,'.base64_encode($ticketQrCode->getString());

        $eventQrCode = (new Builder(
            writer: new PngWriter(),
            data: $eventUrl,
            encoding: new Encoding('UTF-8'),
            size: 150,
            margin: 5,
        ))->build();
        $eventQrBase64 = 'data:image/png;base64,'.base64_encode($eventQrCode->getString());

        $logoBase64 = '';
        if ($organizer->getLogoName()) {
            $logoPath = $this->projectDir.'/public/uploads/logos/'.$organizer->getLogoName();
            if (file_exists($logoPath)) {
                $mime = mime_content_type($logoPath) ?: 'image/png';
                $logoBase64 = 'data:'.$mime.';base64,'.base64_encode((string) file_get_contents($logoPath));
            }
        }

        $posterBase64 = '';
        if ($event->getEventMainPictureName()) {
            $posterPath = $this->projectDir.'/public/uploads/events/'.$event->getEventMainPictureName();
            if (file_exists($posterPath)) {
                $mime = mime_content_type($posterPath) ?: 'image/png';
                $posterBase64 = 'data:'.$mime.';base64,'.base64_encode((string) file_get_contents($posterPath));
            }
        }

        $html = $this->twig->render('pdf/billet.html.twig', [
            'ticket' => $ticket,
            'order' => $order,
            'event' => $event,
            'organizer' => $organizer,
            'design' => $design,
            'qrBase64' => $qrBase64,
            'eventQrBase64' => $eventQrBase64,
            'eventUrl' => $eventUrl,
            'logoBase64' => $logoBase64,
            'posterBase64' => $posterBase64,
        ]);

        $dompdf = new Dompdf();
        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4');
        $dompdf->render();

        return $dompdf->output();
    }

    public function notifyOrganizer(BilletBuyer $order): void
    {
        $organizer = $order->getEvent()->getAccount();
        if (!$organizer || !$organizer->getEmail()) {
            return;
        }

        $html = $this->twig->render('email/order_notification_orga.html.twig', [
            'order' => $order,
        ]);

        $this->mailer->sendEmail(
            $organizer->getEmail(),
            'Nouvelle commande - '.$order->getEvent()->getTitle(),
            $html,
        );
    }

    public function generateAndSendTickets(BilletBuyer $order): void
    {
        $tickets = $this->em->getRepository(BilletOrder::class)->findBy(['billetBuyer' => $order]);
        if (0 === \count($tickets)) {
            return;
        }

        $dir = $this->projectDir.'/var/billets/'.$order->getReference();
        if (!is_dir($dir)) {
            mkdir($dir, 0o755, true);
        }

        $attachments = [];
        foreach ($tickets as $ticket) {
            $billet = $ticket->getBillet();
            if (!$billet || !$billet->isGeneratedBillet()) {
                continue;
            }

            $pdf = $this->generatePdf($ticket);
            $filename = $dir.'/'.$ticket->getReference().'.pdf';
            file_put_contents($filename, $pdf);

            $attachments[] = [
                'path' => $filename,
                'name' => $ticket->getReference().'.pdf',
            ];
        }

        $invoicePath = $this->invoiceService->generateToFile($order);
        $attachments[] = [
            'path' => $invoicePath,
            'name' => 'facture_'.$order->getOrderNumber().'.pdf',
        ];

        $orderUrl = $this->urlGenerator->generate('app_order_public', [
            'orderNumber' => $order->getOrderNumber(),
            'token' => $order->getAccessToken(),
        ], UrlGeneratorInterface::ABSOLUTE_URL);

        $isInvitation = true === $order->isInvitation();

        $html = $this->twig->render('email/order_confirmation.html.twig', [
            'order' => $order,
            'tickets' => $tickets,
            'orderUrl' => $orderUrl,
            'isInvitation' => $isInvitation,
        ]);

        $subject = $isInvitation
            ? 'Votre invitation - '.$order->getEvent()->getTitle()
            : 'Vos billets - '.$order->getEvent()->getTitle();

        $this->mailer->sendEmail(
            $order->getEmail(),
            $subject,
            $html,
            null,
            null,
            false,
            $attachments,
        );
    }
}
