<?php

namespace App\Tests\Service\Pdf;

use App\Entity\Facture;
use App\Entity\FactureLine;
use App\Entity\OrderNumber;
use App\Service\Pdf\FacturePdf;
use Doctrine\Common\Collections\ArrayCollection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\KernelInterface;

class FacturePdfTest extends TestCase
{
    private const HMAC_SECRET = 'test-hmac-secret';

    private KernelInterface $kernel;
    private string $projectDir;

    protected function setUp(): void
    {
        $this->projectDir = sys_get_temp_dir().'/facture-pdf-test-'.bin2hex(random_bytes(4));
        mkdir($this->projectDir.'/public', 0775, true);

        $this->kernel = $this->createStub(KernelInterface::class);
        $this->kernel->method('getProjectDir')->willReturn($this->projectDir);
    }

    protected function tearDown(): void
    {
        $this->removeDir($this->projectDir);
    }

    private function removeDir(string $dir): void
    {
        if (!is_dir($dir)) {
            return;
        }
        foreach (scandir($dir) as $item) {
            if ('.' === $item || '..' === $item) {
                continue;
            }
            $path = $dir.'/'.$item;
            is_dir($path) ? $this->removeDir($path) : unlink($path);
        }
        rmdir($dir);
    }

    private function makeFacture(string $numOrder = '04/2026-00001'): Facture
    {
        $orderNumber = new OrderNumber($numOrder);

        return new Facture($orderNumber, self::HMAC_SECRET);
    }

    private function makeCustomer(bool $withRaisonSociale = false, bool $withAddress2 = false): \App\Entity\Customer
    {
        $customer = $this->createStub(\App\Entity\Customer::class);
        $customer->method('getFullName')->willReturn('Jean Dupont');
        $customer->method('getRaisonSociale')->willReturn($withRaisonSociale ? 'ACME SARL' : null);
        $customer->method('getEmail')->willReturn('jean.dupont@example.com');
        $customer->method('getAddress')->willReturn('42 rue des Tests');
        $customer->method('getAddress2')->willReturn($withAddress2 ? 'Batiment B, etage 3' : null);
        $customer->method('getZipCode')->willReturn('75001');
        $customer->method('getCity')->willReturn('Paris');

        return $customer;
    }

    public function testGenerateEmptyFactureProducesValidPdf(): void
    {
        $facture = $this->makeFacture();
        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithLinesProducesValidPdf(): void
    {
        $facture = $this->makeFacture();
        $facture->setTotalHt('100.00');
        $facture->setTotalTva('0.00');
        $facture->setTotalTtc('100.00');

        $line1 = new FactureLine($facture, 'Hebergement Web', '60.00', 1);
        $line1->setDescription('Hebergement annuel mutualisé');
        $line2 = new FactureLine($facture, 'Nom de domaine', '40.00', 2);
        $line2->setDescription('Renouvellement .fr annuel');

        $facture->getLines()->add($line1);
        $facture->getLines()->add($line2);

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
        $this->assertGreaterThan(1000, \strlen($output));
    }

    public function testGenerateWithCustomerAddressProducesValidPdf(): void
    {
        $facture = $this->makeFacture();
        $facture->setCustomer($this->makeCustomer(false, false));
        $facture->setTotalHt('50.00');
        $facture->setTotalTva('0.00');
        $facture->setTotalTtc('50.00');

        $line = new FactureLine($facture, 'Service test', '50.00', 1);
        $facture->getLines()->add($line);

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithTvaProducesValidPdf(): void
    {
        $facture = $this->makeFacture();
        $facture->setTotalHt('100.00');
        $facture->setTotalTva('20.00');
        $facture->setTotalTtc('120.00');

        $line = new FactureLine($facture, 'Prestation avec TVA', '100.00', 1);
        $facture->getLines()->add($line);

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithPaidFactureProducesValidPdf(): void
    {
        $facture = $this->makeFacture();
        $facture->setTotalHt('200.00');
        $facture->setTotalTva('0.00');
        $facture->setTotalTtc('200.00');
        $facture->setIsPaid(true);
        $facture->setPaidAt(new \DateTimeImmutable('2026-02-15'));
        $facture->setPaidMethod('Virement');

        $line = new FactureLine($facture, 'Service payé', '200.00', 1);
        $facture->getLines()->add($line);

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithLogoFileProducesValidPdf(): void
    {
        // Minimal valid 1x1 JPEG
        $jpegData = base64_decode('/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAACf/EABQQAQAAAAAAAAAAAAAAAAAAAAD/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AJQAB/9k=');
        file_put_contents($this->projectDir.'/public/logo.jpg', $jpegData);

        $facture = $this->makeFacture();
        $line = new FactureLine($facture, 'Test', '10.00', 1);
        $facture->getLines()->add($line);
        $facture->setTotalHt('10.00');
        $facture->setTotalTva('0.00');
        $facture->setTotalTtc('10.00');

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithManyLinesSpansMultiplePages(): void
    {
        $facture = $this->makeFacture();
        $facture->setTotalHt('1500.00');
        $facture->setTotalTva('0.00');
        $facture->setTotalTtc('1500.00');

        for ($i = 1; $i <= 15; ++$i) {
            $line = new FactureLine($facture, 'Service '.$i, '100.00', $i);
            $line->setDescription('Description detaillee pour le service numero '.$i.' avec quelques mots supplementaires.');
            $facture->getLines()->add($line);
        }

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithCustomerRaisonSocialeProducesValidPdf(): void
    {
        $facture = $this->makeFacture();
        $facture->setCustomer($this->makeCustomer(true, true));

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithSplitIndexProducesValidPdf(): void
    {
        $facture = $this->makeFacture('04/2026-00002');
        $facture->setSplitIndex(2);

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithQrCodeProducesValidPdf(): void
    {
        $facture = $this->makeFacture('04/2026-00010');
        $facture->setTotalHt('50.00');
        $facture->setTotalTva('0.00');
        $facture->setTotalTtc('50.00');

        $urlGenerator = $this->createStub(\Symfony\Component\Routing\Generator\UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('https://crm.e-cosplay.fr/facture/verify/1/abc123');

        $line = new FactureLine($facture, 'Service QR', '50.00', 1);
        $facture->getLines()->add($line);

        $pdf = new FacturePdf($this->kernel, $facture, $urlGenerator);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithRibFileProducesValidPdf(): void
    {
        // Create a minimal valid PDF as the RIB file
        $ribDir = $this->projectDir . '/public';
        if (!is_dir($ribDir)) {
            mkdir($ribDir, 0775, true);
        }

        // Create a minimal PDF file for RIB using FPDI itself
        $miniPdf = new \setasign\Fpdi\Fpdi();
        $miniPdf->AddPage();
        $ribPath = $ribDir . '/rib.pdf';
        $miniPdf->Output('F', $ribPath);

        $facture = $this->makeFacture('04/2026-00011');
        $facture->setTotalHt('75.00');
        $facture->setTotalTva('0.00');
        $facture->setTotalTtc('75.00');

        $line = new FactureLine($facture, 'Service RIB', '75.00', 1);
        $facture->getLines()->add($line);

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithTwigAppendsCgvProducesValidPdf(): void
    {
        $facture = $this->makeFacture('04/2026-00012');
        $facture->setTotalHt('80.00');
        $facture->setTotalTva('0.00');
        $facture->setTotalTtc('80.00');

        $line = new FactureLine($facture, 'Service Twig', '80.00', 1);
        $facture->getLines()->add($line);

        // Create a mock Twig environment that returns minimal HTML for CGV
        $twig = $this->createStub(\Twig\Environment::class);
        $twig->method('render')->willReturn('<html><body><p>Conditions Generales de Vente</p></body></html>');

        $pdf = new FacturePdf($this->kernel, $facture, null, $twig);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testGenerateWithCustomerNoAddress(): void
    {
        $facture = $this->makeFacture('04/2026-00013');

        $customer = $this->createStub(\App\Entity\Customer::class);
        $customer->method('getFullName')->willReturn('Jean Dupont');
        $customer->method('getRaisonSociale')->willReturn(null);
        $customer->method('getEmail')->willReturn('jean@example.com');
        $customer->method('getAddress')->willReturn(null); // No address
        $customer->method('getAddress2')->willReturn(null);
        $customer->method('getZipCode')->willReturn(null);
        $customer->method('getCity')->willReturn(null);
        $facture->setCustomer($customer);

        $pdf = new FacturePdf($this->kernel, $facture);
        $pdf->generate();

        $output = $pdf->Output('S');

        $this->assertStringStartsWith('%PDF', $output);
    }

    public function testFooterOnCgvPageSkipsFooter(): void
    {
        // Test that skipHeaderFooter=true makes Footer skip on pages after the last facture page
        $facture = $this->makeFacture('04/2026-00014');
        $facture->setTotalHt('30.00');
        $facture->setTotalTva('0.00');
        $facture->setTotalTtc('30.00');

        $twig = $this->createStub(\Twig\Environment::class);
        $twig->method('render')->willReturn('<html><body><p>CGV page 1</p></body></html>');

        $pdf = new FacturePdf($this->kernel, $facture, null, $twig);
        $pdf->generate();

        $output = $pdf->Output('S');
        $this->assertStringStartsWith('%PDF', $output);
    }

}
