<?php

namespace App\Service\Pdf;

use App\Entity\Advert;
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Writer\PngWriter;
use setasign\Fpdi\Fpdi;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

if (!\defined('EURO')) {
    \define('EURO', \chr(128));
}

class AdvertPdf extends Fpdi
{
    /** @var array<int, array{title: string, content: string, priceHt: float}> */
    private array $items = [];

    private string $qrBase64 = '';
    private bool $skipHeaderFooter = false;
    private int $lastAdvertPage = 0;
    private ?\Twig\Environment $twig = null;

    public function __construct(
        private readonly KernelInterface $kernel,
        private readonly Advert $advert,
        ?UrlGeneratorInterface $urlGenerator = null,
        ?\Twig\Environment $twig = null,
    ) {
        $this->twig = $twig;
        parent::__construct();

        // Generation QR code vers la page de paiement
        if (null !== $urlGenerator) {
            $paymentUrl = $urlGenerator->generate('app_order_payment', [
                'numOrder' => $advert->getOrderNumber()->getNumOrder(),
            ], UrlGeneratorInterface::ABSOLUTE_URL);

            $builder = new Builder(
                writer: new PngWriter(),
                data: $paymentUrl,
                size: 200,
                margin: 10,
            );
            $this->qrBase64 = 'data:image/png;base64,'.base64_encode($builder->build()->getString());
        }

        $items = [];
        foreach ($this->advert->getLines() as $line) {
            $items[$line->getPos()] = [
                'title' => $line->getTitle(),
                'content' => $line->getDescription() ?? '',
                'priceHt' => (float) $line->getPriceHt(),
            ];
        }
        ksort($items);
        $this->items = $items;

        $this->SetTitle($this->enc('Avis de Paiement N° '.$this->advert->getOrderNumber()->getNumOrder()));
    }

    /** @codeCoverageIgnore */
    public function Header(): void
    {
        if ($this->skipHeaderFooter && $this->PageNo() > $this->lastAdvertPage) {
            return;
        }

        $this->SetFont('Arial', '', 10);
        $logo = $this->kernel->getProjectDir().'/public/logo.jpg';
        if (file_exists($logo)) {
            $this->Image($logo, 10, 8, 53);
        }

        $formatter = new \IntlDateFormatter(
            'fr_FR',
            \IntlDateFormatter::FULL,
            \IntlDateFormatter::NONE,
            'Europe/Paris',
            \IntlDateFormatter::GREGORIAN
        );

        $numText = $this->enc('AVIS DE PAIEMENT N° '.$this->advert->getOrderNumber()->getNumOrder());
        $dateText = $this->enc('Emis a Beautor, le '.$formatter->format($this->advert->getCreatedAt()));

        $this->Text(15, 80, $numText);
        $this->Text(15, 85, $dateText);

        $this->SetFont('Arial', 'B', 12);

        $y = 60;
        $customer = $this->advert->getCustomer();

        if (null !== $customer) {
            $name = $customer->getRaisonSociale() ?: $customer->getFullName();
            $this->Text(110, $y, $this->enc($name));

            if ($address = $customer->getAddress()) {
                $y += 5;
                $this->Text(110, $y, $this->enc($address));
            }

            if ($address2 = $customer->getAddress2()) {
                $y += 5;
                $this->Text(110, $y, $this->enc($address2));
            }

            $y += 5;
            $cityLine = ($customer->getZipCode() ?? '').' '.($customer->getCity() ?? '');
            $this->Text(110, $y, $this->enc(trim($cityLine)));
        }

        $this->body();
    }

    /** @codeCoverageIgnore */
    private function body(): void
    {
        $this->SetFont('Arial', 'B', 10);
        $this->SetXY(145, 100);
        $this->Cell(40, 5, $this->enc('PRIX HT'), 0, 0, 'C');

        $this->Line(145, 110, 145, 220);
        $this->Line(185, 110, 185, 220);

        $this->Line(0, 100, 5, 100);
        $this->Line(0, 200, 5, 200);
    }

    public function generate(): void
    {
        $this->AliasNbPages();
        $this->AddPage();
        $this->SetFont('Arial', '', 12);

        $startY = 110;
        $this->SetY($startY);
        $contentBottomLimit = 220;

        foreach ($this->items as $item) {
            if ($this->GetY() + 30 > $contentBottomLimit) {
                $this->AddPage();
                $this->body();
                $this->SetY($startY);
            }

            $currentY = $this->GetY();

            $this->SetX(20);
            $this->SetFont('Arial', 'B', 11);
            $this->Cell(95, 10, $this->enc($item['title']), 0, 0);

            $this->SetFont('Arial', 'B', 11);
            $this->SetXY(142, $currentY);
            $this->Cell(39, 8, number_format($item['priceHt'], 2, ',', ' ').' '.EURO, 0, 1, 'R');

            $this->SetFont('Arial', '', 11);
            $this->SetX(30);
            if ('' !== $item['content']) {
                $this->MultiCell(90, 5, $this->enc($item['content']), 0, 'L');
            }

            $this->Ln(5);
        }

        $this->displaySummary();
        $this->displayQrCode();
        $this->appendCgv();
    }

    /** @codeCoverageIgnore */
    private function appendCgv(): void
    {
        if (null === $this->twig) {
            return;
        }

        try {
            $html = $this->twig->render('pdf/cgv.html.twig');
            $dompdf = new \Dompdf\Dompdf();
            $dompdf->loadHtml($html);
            $dompdf->setPaper('A4');
            $dompdf->render();

            $tmpCgv = tempnam(sys_get_temp_dir(), 'cgv_').'.pdf';
            file_put_contents($tmpCgv, $dompdf->output());

            $this->lastAdvertPage = $this->PageNo();
            $this->skipHeaderFooter = true;
            $pageCount = $this->setSourceFile($tmpCgv);

            for ($i = 1; $i <= $pageCount; ++$i) {
                $tpl = $this->importPage($i);
                $size = $this->getTemplateSize($tpl);
                $this->AddPage($size['orientation'] ?? 'P', [$size['width'], $size['height']]);
                $this->useTemplate($tpl);
            }

            @unlink($tmpCgv);
        } catch (\Throwable) {
            // CGV generation is best-effort
        }
    }

    /** @codeCoverageIgnore */
    private function displayQrCode(): void
    {
        if ('' === $this->qrBase64) {
            return;
        }

        $this->SetAutoPageBreak(false);
        $y = $this->GetPageHeight() - 80;

        // QR code en bas a gauche
        $tmpQr = tempnam(sys_get_temp_dir(), 'qr_').'.png';
        $pngData = base64_decode(str_replace('data:image/png;base64,', '', $this->qrBase64));
        file_put_contents($tmpQr, $pngData);

        $this->Image($tmpQr, 15, $y, 30, 30);
        @unlink($tmpQr);

        // Texte sous le QR code
        $this->SetXY(15, $y + 32);
        $this->SetFont('Arial', 'B', 9);
        $this->SetTextColor(0, 0, 0);
        $this->Cell(50, 5, $this->enc('Scannez pour payer'), 0, 1, 'L');
        $this->SetX(15);
        $this->SetFont('Arial', '', 7);
        $this->SetTextColor(100, 100, 100);
        $this->Cell(60, 4, $this->enc('Flashez ce QR code pour acceder'), 0, 1, 'L');
        $this->SetX(15);
        $this->Cell(60, 4, $this->enc('aux options de paiement.'), 0, 1, 'L');
    }

    /** @codeCoverageIgnore */
    private function displaySummary(): void
    {
        $totalHt = (float) $this->advert->getTotalHt();
        $totalTva = (float) $this->advert->getTotalTva();
        $totalTtc = (float) $this->advert->getTotalTtc();
        $tvaEnabled = $totalTva > 0.01;

        $this->SetY($tvaEnabled ? -60 : -50);

        $this->SetFont('Arial', 'B', 12);
        $this->SetX(105);
        $this->Cell(40, 10, $this->enc('Total HT :'), 0, 0, 'R');
        $this->Cell(40, 10, number_format($totalHt, 2, ',', ' ').' '.EURO, 0, 1, 'R');

        if ($tvaEnabled) {
            $this->SetFont('Arial', '', 12);
            $this->SetX(105);
            $this->Cell(40, 10, $this->enc('TVA (20%) :'), 0, 0, 'R');
            $this->Cell(40, 10, number_format($totalTva, 2, ',', ' ').' '.EURO, 0, 1, 'R');

            $this->SetFont('Arial', 'B', 12);
            $this->SetX(105);
            $this->Cell(40, 10, $this->enc('Total TTC :'), 0, 0, 'R');
            $this->Cell(40, 10, number_format($totalTtc, 2, ',', ' ').' '.EURO, 0, 1, 'R');
        } else {
            $this->SetFont('Arial', '', 8);
            $this->SetX(105);
            $this->Cell(80, 5, $this->enc('TVA non applicable - art. 293 B du CGI'), 0, 1, 'R');
        }
    }

    /** @codeCoverageIgnore */
    public function Footer(): void
    {
        if ($this->skipHeaderFooter && $this->PageNo() > $this->lastAdvertPage) {
            return;
        }

        $this->SetY(-28);
        $this->SetDrawColor(253, 140, 4);
        $this->Line(15, $this->GetY(), 195, $this->GetY());
        $this->Ln(4);
        $this->SetFont('Arial', '', 8);
        $this->SetTextColor(0, 0, 0);
        $this->Cell(190, 4, $this->enc('42 rue de Saint-Quentin - 02800 BEAUTOR - Tél: 07 66 95 70 06'), 0, 1, 'C');
        $this->Cell(190, 4, $this->enc('e-mail : client@e-cosplay.fr - www.e-cosplay.fr'), 0, 1, 'C');
        $this->Cell(190, 4, $this->enc('Association E-Cosplay - N°SIRET 943 121 517 00011 - CODE APE 9329Z - RNA W022006988'), 0, 1, 'C');

        $this->SetFont('Arial', 'I', 7);
        $this->SetTextColor(150, 150, 150);
        $this->Cell(190, 4, $this->enc('Page ').$this->PageNo().' / {nb}', 0, 0, 'C');
    }

    private function enc(string $text): string
    {
        return mb_convert_encoding($text, 'Windows-1252', 'UTF-8');
    }
}
