<?php

namespace App\Tests\Controller\Admin;

use App\Controller\Admin\AdvertController;
use App\Entity\Advert;
use App\Entity\AdvertEvent;
use App\Entity\Customer;
use App\Entity\Devis;
use App\Entity\Facture;
use App\Entity\OrderNumber;
use App\Service\FactureService;
use App\Service\MailerService;
use App\Service\MeilisearchService;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Twig\Environment;

class AdvertControllerTest extends TestCase
{
    // ---------------------------------------------------------------
    // Helper: build controller with container/session
    // ---------------------------------------------------------------

    private function buildController(
        ?EntityManagerInterface $em = null,
        ?MeilisearchService $meilisearch = null,
    ): AdvertController {
        $em ??= $this->createStub(EntityManagerInterface::class);
        $meilisearch ??= $this->createStub(MeilisearchService::class);

        $controller = new AdvertController($em, $meilisearch);

        $session = new Session(new MockArraySessionStorage());
        $stack = $this->createStub(RequestStack::class);
        $stack->method('getSession')->willReturn($session);

        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');

        $router = $this->createStub(RouterInterface::class);
        $router->method('generate')->willReturn('/redirect');

        $container = $this->createStub(ContainerInterface::class);
        $container->method('has')->willReturnMap([
            ['twig', true],
            ['router', true],
            ['security.authorization_checker', true],
            ['security.token_storage', true],
            ['request_stack', true],
            ['parameter_bag', true],
            ['serializer', false],
        ]);
        $container->method('get')->willReturnMap([
            ['twig', $twig],
            ['router', $router],
            ['security.authorization_checker', $this->createStub(AuthorizationCheckerInterface::class)],
            ['security.token_storage', $this->createStub(TokenStorageInterface::class)],
            ['request_stack', $stack],
            ['parameter_bag', $this->createStub(ParameterBagInterface::class)],
        ]);
        $controller->setContainer($container);

        return $controller;
    }

    // ---------------------------------------------------------------
    // Helper: build a real Advert entity
    // ---------------------------------------------------------------

    private function buildAdvert(string $numOrder = 'AP/2026-001'): Advert
    {
        $orderNumber = new OrderNumber($numOrder);
        return new Advert($orderNumber, 'test_secret');
    }

    // ---------------------------------------------------------------
    // events
    // ---------------------------------------------------------------

    public function testEventsThrows404WhenAdvertNotFound(): void
    {
        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn(null);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $this->expectException(NotFoundHttpException::class);
        $controller->events(999);
    }

    public function testEventsRendersTemplate(): void
    {
        $advert = $this->buildAdvert();

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);
        $advertRepo->method('findBy')->willReturn([]);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);
        $response = $controller->events(1);

        $this->assertInstanceOf(Response::class, $response);
        $this->assertSame(200, $response->getStatusCode());
    }

    // ---------------------------------------------------------------
    // generatePdf
    // ---------------------------------------------------------------

    public function testGeneratePdfThrows404WhenAdvertNotFound(): void
    {
        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn(null);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $this->expectException(NotFoundHttpException::class);
        $controller->generatePdf(
            999,
            $this->createStub(KernelInterface::class),
            $this->createStub(UrlGeneratorInterface::class),
            $this->createStub(Environment::class),
        );
    }

    public function testGeneratePdfSuccessWithNoExistingFile(): void
    {
        $tmpDir = sys_get_temp_dir().'/advert_pdf_test_'.uniqid();
        mkdir($tmpDir.'/public/uploads/adverts', 0777, true);

        $advert = $this->buildAdvert('AP/2026-002');
        // no existing advertFile → hadOld = false

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->once())->method('flush');

        $controller = $this->buildController($em);

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

        $urlGenerator = $this->createStub(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('http://localhost/pay/AP-2026-002');

        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');

        $response = $controller->generatePdf(1, $kernel, $urlGenerator, $twig);

        $this->assertSame(302, $response->getStatusCode());

        // Cleanup
        array_map('unlink', glob($tmpDir.'/public/uploads/adverts/*') ?: []);
        @rmdir($tmpDir.'/public/uploads/adverts');
        @rmdir($tmpDir.'/public/uploads');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);
    }

    public function testGeneratePdfSuccessWithExistingFile(): void
    {
        $tmpDir = sys_get_temp_dir().'/advert_pdf_old_'.uniqid();
        mkdir($tmpDir.'/public/uploads/adverts', 0777, true);

        $oldPdfName = 'old-advert.pdf';
        $oldPdfPath = $tmpDir.'/public/uploads/adverts/'.$oldPdfName;
        file_put_contents($oldPdfPath, '%PDF-1.4 old');

        $advert = $this->buildAdvert('AP/2026-003');
        $advert->setAdvertFile($oldPdfName); // hadOld = true, file exists

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->once())->method('flush');

        $controller = $this->buildController($em);

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

        $urlGenerator = $this->createStub(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('http://localhost/pay/AP-2026-003');

        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');

        $response = $controller->generatePdf(1, $kernel, $urlGenerator, $twig);

        $this->assertSame(302, $response->getStatusCode());

        // Cleanup
        array_map('unlink', glob($tmpDir.'/public/uploads/adverts/*') ?: []);
        @rmdir($tmpDir.'/public/uploads/adverts');
        @rmdir($tmpDir.'/public/uploads');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);
    }

    public function testGeneratePdfWithExistingFileNotOnDisk(): void
    {
        // hadOld = true, but file_exists returns false (no unlink branch)
        $tmpDir = sys_get_temp_dir().'/advert_pdf_nof_'.uniqid();
        mkdir($tmpDir.'/public/uploads/adverts', 0777, true);

        $advert = $this->buildAdvert('AP/2026-004');
        $advert->setAdvertFile('missing-file.pdf'); // hadOld = true, file does not exist

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->once())->method('flush');

        $controller = $this->buildController($em);

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

        $urlGenerator = $this->createStub(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('http://localhost/pay/AP-2026-004');

        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');

        $response = $controller->generatePdf(1, $kernel, $urlGenerator, $twig);

        $this->assertSame(302, $response->getStatusCode());

        // Cleanup
        array_map('unlink', glob($tmpDir.'/public/uploads/adverts/*') ?: []);
        @rmdir($tmpDir.'/public/uploads/adverts');
        @rmdir($tmpDir.'/public/uploads');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);
    }

    // ---------------------------------------------------------------
    // send
    // ---------------------------------------------------------------

    public function testSendThrows404WhenAdvertNotFound(): void
    {
        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn(null);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $this->expectException(NotFoundHttpException::class);
        $controller->send(
            999,
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $this->createStub(UrlGeneratorInterface::class),
            '/tmp',
        );
    }

    public function testSendRedirectsWhenNoPdf(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(5);

        $advert = $this->buildAdvert();
        $advert->setCustomer($customer);
        // advertFile is null by default

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->send(
            1,
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $this->createStub(UrlGeneratorInterface::class),
            '/tmp',
        );

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testSendRedirectsWhenCustomerIsNull(): void
    {
        $advert = $this->buildAdvert();
        $advert->setAdvertFile('some.pdf');
        // customer = null

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->send(
            1,
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $this->createStub(UrlGeneratorInterface::class),
            '/tmp',
        );

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testSendRedirectsWhenCustomerEmailIsNull(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(3);
        $customer->method('getEmail')->willReturn(null);

        $advert = $this->buildAdvert();
        $advert->setAdvertFile('some.pdf');
        $advert->setCustomer($customer);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->send(
            1,
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $this->createStub(UrlGeneratorInterface::class),
            '/tmp',
        );

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testSendSuccessfully(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(7);
        $customer->method('getEmail')->willReturn('client@test.com');

        $advert = $this->buildAdvert('AP/2026-010');
        $advert->setAdvertFile('advert.pdf');
        $advert->setCustomer($customer);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $meilisearch = $this->createStub(MeilisearchService::class);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->exactly(2))->method('flush');
        $em->expects($this->once())->method('persist');

        $controller = $this->buildController($em, $meilisearch);

        $mailer = $this->createStub(MailerService::class);
        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');
        $urlGenerator = $this->createStub(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('http://localhost/pay/AP-2026-010');

        $response = $controller->send(1, $mailer, $twig, $urlGenerator, '/tmp');

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testSendSuccessfullyWithPdfFileOnDisk(): void
    {
        $tmpDir = sys_get_temp_dir().'/advert_send_test_'.uniqid();
        mkdir($tmpDir.'/public/uploads/adverts', 0777, true);
        $pdfFileName = 'advert-test.pdf';
        file_put_contents($tmpDir.'/public/uploads/adverts/'.$pdfFileName, '%PDF-1.4 test');

        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(8);
        $customer->method('getEmail')->willReturn('pdf@test.com');

        $advert = $this->buildAdvert('AP/2026-011');
        $advert->setAdvertFile($pdfFileName);
        $advert->setCustomer($customer);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $meilisearch = $this->createStub(MeilisearchService::class);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->exactly(2))->method('flush');

        $controller = $this->buildController($em, $meilisearch);

        $mailer = $this->createStub(MailerService::class);
        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');
        $urlGenerator = $this->createStub(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('http://localhost/pay/AP-2026-011');

        $response = $controller->send(1, $mailer, $twig, $urlGenerator, $tmpDir);

        @unlink($tmpDir.'/public/uploads/adverts/'.$pdfFileName);
        @rmdir($tmpDir.'/public/uploads/adverts');
        @rmdir($tmpDir.'/public/uploads');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);

        $this->assertSame(302, $response->getStatusCode());
    }

    // ---------------------------------------------------------------
    // resend
    // ---------------------------------------------------------------

    public function testResendThrows404WhenAdvertNotFound(): void
    {
        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn(null);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $this->expectException(NotFoundHttpException::class);
        $controller->resend(
            999,
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $this->createStub(UrlGeneratorInterface::class),
            '/tmp',
        );
    }

    public function testResendRedirectsWhenCustomerIsNull(): void
    {
        $advert = $this->buildAdvert();
        // customer = null

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->resend(
            1,
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $this->createStub(UrlGeneratorInterface::class),
            '/tmp',
        );

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testResendRedirectsWhenCustomerEmailIsNull(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(4);
        $customer->method('getEmail')->willReturn(null);

        $advert = $this->buildAdvert();
        $advert->setCustomer($customer);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->resend(
            1,
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $this->createStub(UrlGeneratorInterface::class),
            '/tmp',
        );

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testResendRedirectsWhenNoPdf(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(6);
        $customer->method('getEmail')->willReturn('client@test.com');

        $advert = $this->buildAdvert();
        $advert->setCustomer($customer);
        // advertFile = null

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->resend(
            1,
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $this->createStub(UrlGeneratorInterface::class),
            '/tmp',
        );

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testResendSuccessfully(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(9);
        $customer->method('getEmail')->willReturn('resend@test.com');

        $advert = $this->buildAdvert('AP/2026-020');
        $advert->setAdvertFile('advert-20.pdf');
        $advert->setCustomer($customer);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->once())->method('flush');
        $em->expects($this->once())->method('persist');

        $controller = $this->buildController($em);

        $mailer = $this->createStub(MailerService::class);
        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');
        $urlGenerator = $this->createStub(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('http://localhost/pay/AP-2026-020');

        $response = $controller->resend(1, $mailer, $twig, $urlGenerator, '/tmp');

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testResendSuccessfullyWithPdfFileOnDisk(): void
    {
        $tmpDir = sys_get_temp_dir().'/advert_resend_test_'.uniqid();
        mkdir($tmpDir.'/public/uploads/adverts', 0777, true);
        $pdfFileName = 'advert-resend.pdf';
        file_put_contents($tmpDir.'/public/uploads/adverts/'.$pdfFileName, '%PDF-1.4 resend');

        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(10);
        $customer->method('getEmail')->willReturn('resend-disk@test.com');

        $advert = $this->buildAdvert('AP/2026-021');
        $advert->setAdvertFile($pdfFileName);
        $advert->setCustomer($customer);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->once())->method('flush');

        $controller = $this->buildController($em);

        $mailer = $this->createStub(MailerService::class);
        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');
        $urlGenerator = $this->createStub(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('http://localhost/pay/AP-2026-021');

        $response = $controller->resend(1, $mailer, $twig, $urlGenerator, $tmpDir);

        @unlink($tmpDir.'/public/uploads/adverts/'.$pdfFileName);
        @rmdir($tmpDir.'/public/uploads/adverts');
        @rmdir($tmpDir.'/public/uploads');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);

        $this->assertSame(302, $response->getStatusCode());
    }

    // ---------------------------------------------------------------
    // search
    // ---------------------------------------------------------------

    public function testSearchReturnsEmptyWhenQueryBlank(): void
    {
        $controller = $this->buildController();

        $request = new Request(['q' => '']);
        $response = $controller->search(1, $request);

        $this->assertInstanceOf(JsonResponse::class, $response);
        $this->assertSame('[]', $response->getContent());
    }

    public function testSearchReturnsEmptyWhenQueryWhitespaceOnly(): void
    {
        $controller = $this->buildController();

        $request = new Request(['q' => '   ']);
        $response = $controller->search(1, $request);

        $this->assertInstanceOf(JsonResponse::class, $response);
        $this->assertSame('[]', $response->getContent());
    }

    public function testSearchReturnsMeilisearchResults(): void
    {
        $hits = [['id' => 1, 'orderNumber' => 'AP/2026-001']];

        $meilisearch = $this->createStub(MeilisearchService::class);
        $meilisearch->method('searchAdverts')->willReturn($hits);

        $controller = $this->buildController(null, $meilisearch);

        $request = new Request(['q' => 'AP']);
        $response = $controller->search(1, $request);

        $this->assertInstanceOf(JsonResponse::class, $response);
        $data = json_decode($response->getContent(), true);
        $this->assertCount(1, $data);
        $this->assertSame('AP/2026-001', $data[0]['orderNumber']);
    }

    public function testSearchPassesCustomerIdFilter(): void
    {
        $meilisearch = $this->createMock(MeilisearchService::class);
        $meilisearch->expects($this->once())
            ->method('searchAdverts')
            ->with('test', 20, 42)
            ->willReturn([]);

        $controller = $this->buildController(null, $meilisearch);

        $request = new Request(['q' => 'test']);
        $response = $controller->search(42, $request);

        $this->assertInstanceOf(JsonResponse::class, $response);
    }

    // ---------------------------------------------------------------
    // createFacture
    // ---------------------------------------------------------------

    public function testCreateFactureThrows404WhenAdvertNotFound(): void
    {
        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn(null);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $this->expectException(NotFoundHttpException::class);
        $controller->createFacture(999, $this->createStub(FactureService::class));
    }

    public function testCreateFactureRedirectsWhenStateNotAccepted(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(5);

        $advert = $this->buildAdvert();
        $advert->setState(Advert::STATE_CREATED);
        $advert->setCustomer($customer);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->createFacture(1, $this->createStub(FactureService::class));

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testCreateFactureRedirectsWhenFactureAlreadyExists(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(5);

        $advert = $this->createMock(Advert::class);
        $advert->method('getState')->willReturn(Advert::STATE_ACCEPTED);
        $advert->method('getCustomer')->willReturn($customer);

        $existingFacture = $this->createStub(Facture::class);
        $collection = new ArrayCollection([$existingFacture]);
        $advert->method('getFactures')->willReturn($collection);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->createFacture(1, $this->createStub(FactureService::class));

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testCreateFactureSuccessfully(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(5);

        $advert = $this->createMock(Advert::class);
        $advert->method('getState')->willReturn(Advert::STATE_ACCEPTED);
        $advert->method('getCustomer')->willReturn($customer);
        $advert->method('getFactures')->willReturn(new ArrayCollection([]));

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $facture = $this->createStub(Facture::class);
        $facture->method('getInvoiceNumber')->willReturn('F-2026-001');

        $factureService = $this->createStub(FactureService::class);
        $factureService->method('createFromAdvert')->willReturn($facture);

        $response = $controller->createFacture(1, $factureService);

        $this->assertSame(302, $response->getStatusCode());
    }

    // ---------------------------------------------------------------
    // syncPayment — only public-method guard paths (processSyncPayment is @codeCoverageIgnore)
    // ---------------------------------------------------------------

    public function testSyncPaymentThrows404WhenAdvertNotFound(): void
    {
        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn(null);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $this->expectException(NotFoundHttpException::class);
        $controller->syncPayment(999, $this->createStub(FactureService::class), 'sk_test_123');
    }

    public function testSyncPaymentRedirectsWhenNoPiId(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(5);

        $advert = $this->buildAdvert();
        $advert->setCustomer($customer);
        // stripePaymentId = null

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->syncPayment(1, $this->createStub(FactureService::class), 'sk_test_123');

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testSyncPaymentRedirectsWhenStripeSkEmpty(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(5);

        $advert = $this->buildAdvert();
        $advert->setCustomer($customer);
        $advert->setStripePaymentId('pi_test_123');

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->syncPayment(1, $this->createStub(FactureService::class), '');

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testSyncPaymentWithValidPiIdAndStripeSkExecutesTryBlock(): void
    {
        // When piId and stripeSk are both present, syncPayment calls processSyncPayment.
        // processSyncPayment calls Stripe API which throws in the test environment.
        // The catch block in syncPayment handles the exception and redirects.
        // This covers the try/catch and final redirect lines in syncPayment.
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(7);

        $advert = $this->buildAdvert();
        $advert->setCustomer($customer);
        $advert->setStripePaymentId('pi_test_valid_123');

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        // Stripe API will throw an exception (not configured in test env) → caught by catch block
        $response = $controller->syncPayment(1, $this->createStub(FactureService::class), 'sk_live_fake_key_for_test');

        $this->assertSame(302, $response->getStatusCode());
    }

    // ---------------------------------------------------------------
    // cancel
    // ---------------------------------------------------------------

    public function testCancelThrows404WhenAdvertNotFound(): void
    {
        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn(null);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $this->expectException(NotFoundHttpException::class);
        $controller->cancel(999);
    }

    public function testCancelAddsFlashWhenAlreadyCancelled(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(5);

        $advert = $this->buildAdvert();
        $advert->setState(Advert::STATE_CANCEL);
        $advert->setCustomer($customer);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $em = $this->createStub(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);

        $controller = $this->buildController($em);

        $response = $controller->cancel(1);

        $this->assertSame(302, $response->getStatusCode());
    }

    public function testCancelSuccessfullyWithDevis(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(5);

        $devis = $this->createMock(Devis::class);
        $devis->expects($this->once())->method('setAdvert')->with(null);

        $advert = $this->buildAdvert('AP/2026-030');
        $advert->setState(Advert::STATE_SEND);
        $advert->setCustomer($customer);
        $advert->setDevis($devis);

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $meilisearch = $this->createMock(MeilisearchService::class);
        $meilisearch->expects($this->once())->method('indexAdvert')->with($advert);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->once())->method('flush');

        $controller = $this->buildController($em, $meilisearch);

        $response = $controller->cancel(1);

        $this->assertSame(302, $response->getStatusCode());
        $this->assertSame(Advert::STATE_CANCEL, $advert->getState());
        $this->assertNull($advert->getDevis());
    }

    public function testCancelSuccessfullyWithoutDevis(): void
    {
        $customer = $this->createStub(Customer::class);
        $customer->method('getId')->willReturn(6);

        $advert = $this->buildAdvert('AP/2026-031');
        $advert->setState(Advert::STATE_CREATED);
        $advert->setCustomer($customer);
        // devis = null

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $meilisearch = $this->createStub(MeilisearchService::class);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->once())->method('flush');

        $controller = $this->buildController($em, $meilisearch);

        $response = $controller->cancel(1);

        $this->assertSame(302, $response->getStatusCode());
        $this->assertSame(Advert::STATE_CANCEL, $advert->getState());
    }

    public function testCancelWithNullCustomerRedirectsToIndex(): void
    {
        $advert = $this->buildAdvert('AP/2026-032');
        $advert->setState(Advert::STATE_CREATED);
        // customer = null

        $advertRepo = $this->createStub(EntityRepository::class);
        $advertRepo->method('find')->willReturn($advert);

        $meilisearch = $this->createStub(MeilisearchService::class);

        $em = $this->createMock(EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($advertRepo);
        $em->expects($this->once())->method('flush');

        $controller = $this->buildController($em, $meilisearch);

        $response = $controller->cancel(1);

        $this->assertSame(302, $response->getStatusCode());
    }
}
