<?php

namespace App\Tests\Service;

use App\Entity\BilletBuyer;
use App\Entity\BilletBuyerItem;
use App\Entity\Event;
use App\Entity\User;
use App\Service\ExportService;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Twig\Environment;

class ExportServiceTest extends TestCase
{
    private function createMockOrder(float $totalHtEuros = 50.0, float $commissionRate = 3.0, string $orderNumber = '2026-03-01-1'): BilletBuyer
    {
        $user = $this->createMock(User::class);
        $user->method('getCommissionRate')->willReturn($commissionRate);
        $user->method('getCompanyName')->willReturn('Asso Test');
        $user->method('getFirstName')->willReturn('Orga');

        $event = $this->createMock(Event::class);
        $event->method('getAccount')->willReturn($user);
        $event->method('getTitle')->willReturn('Event Test');

        $item = $this->createMock(BilletBuyerItem::class);
        $item->method('getBilletName')->willReturn('Entree');
        $item->method('getQuantity')->willReturn(2);

        $order = $this->createMock(BilletBuyer::class);
        $order->method('getTotalHT')->willReturn((int) ($totalHtEuros * 100));
        $order->method('getEvent')->willReturn($event);
        $order->method('getOrderNumber')->willReturn($orderNumber);
        $order->method('getPaidAt')->willReturn(new \DateTimeImmutable('2026-03-15 14:30'));
        $order->method('getFirstName')->willReturn('Jean');
        $order->method('getLastName')->willReturn('Dupont');
        $order->method('getEmail')->willReturn('jean@example.com');
        $order->method('getItems')->willReturn(new ArrayCollection([$item]));

        return $order;
    }

    public function testGenerateCsvOrga(): void
    {
        $em = $this->createMock(EntityManagerInterface::class);
        $twig = $this->createMock(Environment::class);

        $service = new ExportService($em, $twig);
        $order = $this->createMockOrder(50.0, 3.0);

        $csv = $service->generateCsv([$order], false);
        $lines = explode("\n", $csv);

        self::assertCount(2, $lines);
        self::assertStringContainsString('Commande', $lines[0]);
        self::assertStringContainsString('Net percu', $lines[0]);
        self::assertStringNotContainsString('Organisateur', $lines[0]);
        self::assertStringContainsString('2026-03-01-1', $lines[1]);
        self::assertStringContainsString('Jean Dupont', $lines[1]);
        self::assertStringContainsString('Entree x2', $lines[1]);
        self::assertStringContainsString('50,00', $lines[1]);
    }

    public function testGenerateCsvAdmin(): void
    {
        $em = $this->createMock(EntityManagerInterface::class);
        $twig = $this->createMock(Environment::class);

        $service = new ExportService($em, $twig);
        $order = $this->createMockOrder();

        $csv = $service->generateCsv([$order], true);
        $lines = explode("\n", $csv);

        self::assertCount(2, $lines);
        self::assertStringContainsString('Organisateur', $lines[0]);
        self::assertStringNotContainsString('Net percu', $lines[0]);
        self::assertStringContainsString('Asso Test', $lines[1]);
    }

    public function testGenerateCsvEmptyOrders(): void
    {
        $em = $this->createMock(EntityManagerInterface::class);
        $twig = $this->createMock(Environment::class);

        $service = new ExportService($em, $twig);

        $csv = $service->generateCsv([], false);
        $lines = explode("\n", $csv);

        self::assertCount(1, $lines);
        self::assertStringContainsString('Commande', $lines[0]);
    }

    public function testGenerateCsvCommissionCalculation(): void
    {
        $em = $this->createMock(EntityManagerInterface::class);
        $twig = $this->createMock(Environment::class);

        $service = new ExportService($em, $twig);
        $order = $this->createMockOrder(100.0, 2.0);

        $csv = $service->generateCsv([$order], false);
        $lines = explode("\n", $csv);
        $cols = explode(';', $lines[1]);

        // Total HT = 100.00
        self::assertSame('100,00', $cols[6]);
        // Com E-Ticket = 100 * 2% = 2.00
        self::assertSame('2,00', $cols[7]);
        // Com Stripe = 100 * 1.5% + 0.25 = 1.75
        self::assertSame('1,75', $cols[8]);
        // Net = 100 - 2 - 1.75 = 96.25
        self::assertSame('96,25', $cols[9]);
    }

    public function testGenerateCsvNullCommissionRateDefaults3(): void
    {
        $em = $this->createMock(EntityManagerInterface::class);
        $twig = $this->createMock(Environment::class);

        $user = $this->createMock(User::class);
        $user->method('getCommissionRate')->willReturn(null);
        $user->method('getCompanyName')->willReturn('Test');

        $event = $this->createMock(Event::class);
        $event->method('getAccount')->willReturn($user);
        $event->method('getTitle')->willReturn('Event');

        $item = $this->createMock(BilletBuyerItem::class);
        $item->method('getBilletName')->willReturn('Billet');
        $item->method('getQuantity')->willReturn(1);

        $order = $this->createMock(BilletBuyer::class);
        $order->method('getTotalHT')->willReturn(10000);
        $order->method('getEvent')->willReturn($event);
        $order->method('getOrderNumber')->willReturn('2026-03-01-2');
        $order->method('getPaidAt')->willReturn(new \DateTimeImmutable());
        $order->method('getFirstName')->willReturn('A');
        $order->method('getLastName')->willReturn('B');
        $order->method('getEmail')->willReturn('a@b.com');
        $order->method('getItems')->willReturn(new ArrayCollection([$item]));

        $service = new ExportService($em, $twig);
        $csv = $service->generateCsv([$order], false);
        $cols = explode(';', explode("\n", $csv)[1]);

        // Com E-Ticket = 100 * 3% = 3.00 (default)
        self::assertSame('3,00', $cols[7]);
    }

    public function testGeneratePdfReturnsPdfContent(): void
    {
        $em = $this->createMock(EntityManagerInterface::class);
        $twig = $this->createMock(Environment::class);
        $twig->method('render')->willReturn('<html><body><h1>Test</h1></body></html>');

        $service = new ExportService($em, $twig);

        $stats = [
            'orders' => [],
            'totalHT' => 100.0,
            'commissionEticket' => 3.0,
            'commissionStripe' => 1.75,
            'netOrga' => 95.25,
        ];

        $pdf = $service->generatePdf($stats, 2026, 3);

        self::assertNotEmpty($pdf);
        self::assertStringStartsWith('%PDF', $pdf);
    }

    public function testGeneratePdfWithOrganizer(): void
    {
        $em = $this->createMock(EntityManagerInterface::class);
        $twig = $this->createMock(Environment::class);

        $organizer = $this->createMock(User::class);

        $twig->expects($this->once())->method('render')->with(
            'pdf/export_recap.html.twig',
            $this->callback(function (array $params) use ($organizer) {
                return $params['organizer'] === $organizer
                    && false === $params['isAdmin']
                    && 2026 === $params['year']
                    && 3 === $params['month'];
            })
        )->willReturn('<html><body>test</body></html>');

        $service = new ExportService($em, $twig);

        $stats = ['orders' => [], 'totalHT' => 0, 'commissionEticket' => 0, 'commissionStripe' => 0, 'netOrga' => 0];
        $pdf = $service->generatePdf($stats, 2026, 3, $organizer);

        self::assertStringStartsWith('%PDF', $pdf);
    }

    public function testGeneratePdfAdmin(): void
    {
        $em = $this->createMock(EntityManagerInterface::class);
        $twig = $this->createMock(Environment::class);

        $twig->expects($this->once())->method('render')->with(
            'pdf/export_recap.html.twig',
            $this->callback(fn (array $params) => true === $params['isAdmin'] && null === $params['organizer'])
        )->willReturn('<html><body>admin</body></html>');

        $service = new ExportService($em, $twig);

        $stats = ['orders' => [], 'totalHT' => 0, 'commissionEticket' => 0, 'commissionStripe' => 0, 'netOrga' => 0];
        $service->generatePdf($stats, 2026, 3);
    }

    public function testGenerateCsvMultipleOrders(): void
    {
        $em = $this->createMock(EntityManagerInterface::class);
        $twig = $this->createMock(Environment::class);

        $service = new ExportService($em, $twig);

        $order1 = $this->createMockOrder(50.0, 3.0, '2026-03-01-1');
        $order2 = $this->createMockOrder(100.0, 2.0, '2026-03-01-2');

        $csv = $service->generateCsv([$order1, $order2], false);
        $lines = explode("\n", $csv);

        self::assertCount(3, $lines);
        self::assertStringContainsString('2026-03-01-1', $lines[1]);
        self::assertStringContainsString('2026-03-01-2', $lines[2]);
    }
}
