<?php

namespace App\Tests\Controller\Admin;

use App\Controller\Admin\ClientsController;
use App\Entity\Customer;
use App\Entity\User;
use App\Repository\CustomerRepository;
use App\Service\MailerService;
use App\Service\MeilisearchService;
use App\Service\UserManagementService;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
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\Routing\RouterInterface;
use Twig\Environment;

class ClientsControllerTest extends TestCase
{
    private function createController(?Request $request = null): ClientsController
    {
        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');

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

        $requestStack = new RequestStack();
        if (null !== $request) {
            $requestStack->push($request);
        }

        $container = $this->createStub(ContainerInterface::class);
        $container->method('has')->willReturn(true);
        $container->method('get')->willReturnMap([
            ['twig', $twig],
            ['router', $router],
            ['request_stack', $requestStack],
        ]);

        $controller = new ClientsController();
        $controller->setContainer($container);

        return $controller;
    }

    public function testIndex(): void
    {
        $repo = $this->createStub(CustomerRepository::class);
        $repo->method('findBy')->willReturn([]);

        $em = $this->createStub(EntityManagerInterface::class);

        $controller = $this->createController();
        $response = $controller->index($repo, $em);

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

    public function testIndexWithCustomersAndDomains(): void
    {
        $user = new \App\Entity\User();
        $user->setEmail('idx@test.com');
        $user->setFirstName('I');
        $user->setLastName('D');
        $user->setPassword('h');
        $customer = new \App\Entity\Customer($user);
        $ref = new \ReflectionProperty(\App\Entity\Customer::class, 'id');
        $ref->setAccessible(true);
        $ref->setValue($customer, 42);

        $domain = $this->createStub(\App\Entity\Domain::class);

        $repo = $this->createStub(CustomerRepository::class);
        $repo->method('findBy')->willReturn([$customer]);

        $domainRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $domainRepo->method('findBy')->willReturn([$domain]);

        $emailRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $emailRepo->method('count')->willReturn(2); // has emails

        $websiteRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $websiteRepo->method('count')->willReturn(1);
        $websiteRepo->method('findBy')->willReturn([]);

        $em = $this->createStub(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturnCallback(function (string $entity) use ($domainRepo, $emailRepo, $websiteRepo) {
            return match ($entity) {
                \App\Entity\Domain::class => $domainRepo,
                \App\Entity\DomainEmail::class => $emailRepo,
                \App\Entity\Website::class => $websiteRepo,
                default => $domainRepo,
            };
        });

        $controller = $this->createController();
        $response = $controller->index($repo, $em);

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

    public function testCreateGet(): void
    {
        $controller = $this->createController();
        $request = new Request();
        $request->setMethod('GET');

        $repo = $this->createStub(CustomerRepository::class);
        $em = $this->createStub(EntityManagerInterface::class);
        $meilisearch = $this->createStub(MeilisearchService::class);
        $userService = $this->createStub(UserManagementService::class);
        $logger = $this->createStub(LoggerInterface::class);

        $response = $controller->create($request, $repo, $this->createStub(\App\Repository\RevendeurRepository::class), $em, $meilisearch, $userService, $logger, $this->createStub(HttpClientInterface::class), $this->createStub(MailerService::class), $this->createStub(Environment::class), 'sk_test_***');

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

    public function testCreatePostInvalidData(): void
    {
        $request = new Request([], ['firstName' => '', 'lastName' => '', 'email' => '']);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $repo = $this->createStub(CustomerRepository::class);
        $em = $this->createStub(EntityManagerInterface::class);
        $meilisearch = $this->createStub(MeilisearchService::class);
        $userService = $this->createStub(UserManagementService::class);
        $userService->method('createBaseUser')->willThrowException(new \InvalidArgumentException('Champs requis'));
        $logger = $this->createStub(LoggerInterface::class);

        $response = $controller->create($request, $repo, $this->createStub(\App\Repository\RevendeurRepository::class), $em, $meilisearch, $userService, $logger, $this->createStub(HttpClientInterface::class), $this->createStub(MailerService::class), $this->createStub(Environment::class), 'sk_test_***');

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

    public function testCreatePostThrowsGenericError(): void
    {
        $request = new Request([], ['firstName' => 'Test', 'lastName' => 'User', 'email' => 'test@test.com']);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $repo = $this->createStub(CustomerRepository::class);
        $em = $this->createStub(EntityManagerInterface::class);
        $meilisearch = $this->createStub(MeilisearchService::class);
        $userService = $this->createStub(UserManagementService::class);
        $userService->method('createBaseUser')->willThrowException(new \RuntimeException('DB error'));
        $logger = $this->createStub(LoggerInterface::class);

        $response = $controller->create($request, $repo, $this->createStub(\App\Repository\RevendeurRepository::class), $em, $meilisearch, $userService, $logger, $this->createStub(HttpClientInterface::class), $this->createStub(MailerService::class), $this->createStub(Environment::class), 'sk_test_***');

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

    public function testSearchEmpty(): void
    {
        $meilisearch = $this->createStub(MeilisearchService::class);
        $controller = $this->createController();

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

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

    public function testSearchWithQuery(): void
    {
        $meilisearch = $this->createStub(MeilisearchService::class);
        $meilisearch->method('searchCustomers')->willReturn([['id' => 1, 'fullName' => 'John Doe']]);

        $controller = $this->createController();
        $request = new Request(['q' => 'John']);
        $response = $controller->search($request, $meilisearch);

        $this->assertInstanceOf(JsonResponse::class, $response);
        $this->assertStringContainsString('John Doe', $response->getContent());
    }

    public function testEntrepriseSearchTooShort(): void
    {
        $svc = $this->createMock(\App\Service\EntrepriseSearchService::class);
        $svc->method('search')->willReturn(new JsonResponse(['results' => [], 'total_results' => 0]));

        $controller = new ClientsController();
        $response = $controller->entrepriseSearch(new Request(['q' => 'a']), $svc);
        $this->assertStringContainsString('"total_results":0', $response->getContent());
    }

    public function testEntrepriseSearchSuccess(): void
    {
        $svc = $this->createMock(\App\Service\EntrepriseSearchService::class);
        $svc->method('search')->willReturn(new JsonResponse(['results' => [['siren' => '123456789']], 'total_results' => 1]));

        $controller = new ClientsController();
        $response = $controller->entrepriseSearch(new Request(['q' => 'siteconseil']), $svc);
        $this->assertStringContainsString('123456789', $response->getContent());
    }

    public function testEntrepriseSearchApiError(): void
    {
        $svc = $this->createMock(\App\Service\EntrepriseSearchService::class);
        $svc->method('search')->willReturn(new JsonResponse(['error' => 'Service indisponible'], 502));

        $controller = new ClientsController();
        $response = $controller->entrepriseSearch(new Request(['q' => 'test']), $svc);
        $this->assertSame(502, $response->getStatusCode());
    }

    public function testToggle(): void
    {
        $user = new User();
        $user->setEmail('t@t.com');
        $user->setFirstName('T');
        $user->setLastName('T');
        $user->setPassword('h');
        $customer = new Customer($user);

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));

        $em = $this->createMock(EntityManagerInterface::class);
        $em->expects($this->once())->method('flush');
        $meilisearch = $this->createStub(MeilisearchService::class);
        $logger = $this->createStub(LoggerInterface::class);

        $controller = $this->createController($request);

        $response = $controller->toggle($customer, $em, $meilisearch, $logger);
        $this->assertSame(302, $response->getStatusCode());
        $this->assertFalse($customer->isActive());
    }

    public function testToggleSuspendedToActive(): void
    {
        $user = new User();
        $user->setEmail('t@t.com');
        $user->setFirstName('T');
        $user->setLastName('T');
        $user->setPassword('h');
        $customer = new Customer($user);
        $customer->setState(Customer::STATE_SUSPENDED);

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->toggle($customer, $this->createStub(EntityManagerInterface::class), $this->createStub(MeilisearchService::class), $this->createStub(LoggerInterface::class));
        $this->assertSame(302, $response->getStatusCode());
        $this->assertTrue($customer->isActive());
    }

    public function testToggleMeilisearchError(): void
    {
        $user = new User();
        $user->setEmail('t@t.com');
        $user->setFirstName('T');
        $user->setLastName('T');
        $user->setPassword('h');
        $customer = new Customer($user);

        $meilisearch = $this->createStub(MeilisearchService::class);
        $meilisearch->method('indexCustomer')->willThrowException(new \RuntimeException('Meili down'));

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->toggle($customer, $this->createStub(EntityManagerInterface::class), $meilisearch, $this->createStub(LoggerInterface::class));
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testCreatePostSuccessNoStripe(): void
    {
        $user = new User();
        $user->setEmail('new@test.com');
        $user->setFirstName('Jean');
        $user->setLastName('Client');
        $user->setPassword('h');

        $userService = $this->createStub(UserManagementService::class);
        $userService->method('createBaseUser')->willReturn($user);

        $repo = $this->createStub(CustomerRepository::class);
        $repo->method('generateUniqueCodeComptable')->willReturn('CLI-00001');

        $request = new Request([], [
            'firstName' => 'Jean',
            'lastName' => 'Client',
            'email' => 'new@test.com',
            'phone' => '0612345678',
            'raisonSociale' => 'Ma SARL',
            'siret' => '12345678901234',
            'rcs' => 'RCS Paris',
            'numTva' => 'FR12345678901',
            'address' => '1 rue Test',
            'address2' => 'Bat A',
            'zipCode' => '75001',
            'city' => 'Paris',
            'typeCompany' => 'SARL',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->create(
            $request,
            $repo,
            $this->createStub(\App\Repository\RevendeurRepository::class),
            $this->createStub(EntityManagerInterface::class),
            $this->createStub(MeilisearchService::class),
            $userService,
            $this->createStub(LoggerInterface::class),
            $this->createStub(HttpClientInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            '',
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testCreatePostSuccessStripeBypass(): void
    {
        $user = new User();
        $user->setEmail('a@b.com');
        $user->setFirstName('A');
        $user->setLastName('B');
        $user->setPassword('h');

        $userService = $this->createStub(UserManagementService::class);
        $userService->method('createBaseUser')->willReturn($user);

        $repo = $this->createStub(CustomerRepository::class);
        $repo->method('generateUniqueCodeComptable')->willReturn('CLI-00002');

        $request = new Request([], [
            'firstName' => 'A', 'lastName' => 'B', 'email' => 'a@b.com',
            'phone' => '', 'raisonSociale' => '', 'siret' => '', 'rcs' => '',
            'numTva' => '', 'address' => '', 'address2' => '', 'zipCode' => '',
            'city' => '', 'typeCompany' => '',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->create(
            $request,
            $repo,
            $this->createStub(\App\Repository\RevendeurRepository::class),
            $this->createStub(EntityManagerInterface::class),
            $this->createStub(MeilisearchService::class),
            $userService,
            $this->createStub(LoggerInterface::class),
            $this->createStub(HttpClientInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            'sk_test_***',
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    private function buildCustomer(int $id = 1): Customer
    {
        $user = new User();
        $user->setEmail('show@test.com');
        $user->setFirstName('Show');
        $user->setLastName('User');
        $user->setPassword('h');
        $customer = new Customer($user);
        $ref = new \ReflectionProperty(Customer::class, 'id');
        $ref->setAccessible(true);
        $ref->setValue($customer, $id);

        return $customer;
    }

    public function testShowReturnsResponse(): void
    {
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);
        $entityRepo->method('find')->willReturn(null);

        $em = $this->createStub(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);

        $request = new Request();
        $request->setMethod('GET');

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertInstanceOf(Response::class, $response);
    }

    public function testShowPostInfo(): void
    {
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);

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

        $request = new Request(['tab' => 'info'], ['firstName' => 'Updated', 'lastName' => 'Name', 'email' => 'u@t.com']);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testDeleteMarksForDeletion(): void
    {
        $customer = $this->buildCustomer();

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->expects($this->once())->method('flush');

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));
        $controller = $this->createController($request);

        $response = $controller->delete($customer, $em);
        $this->assertSame(302, $response->getStatusCode());
        $this->assertTrue($customer->isPendingDelete());
    }

    public function testDeleteAlreadyPendingDelete(): void
    {
        $user = new User();
        $user->setEmail('p@t.com');
        $user->setFirstName('P');
        $user->setLastName('D');
        $user->setPassword('h');
        $customer = new Customer($user);
        $customer->setState(Customer::STATE_PENDING_DELETE);

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->expects($this->never())->method('flush');

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));
        $controller = $this->createController($request);

        $response = $controller->delete($customer, $em);
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testResendWelcomeWithTempPassword(): void
    {
        $user = new User();
        $user->setEmail('w@t.com');
        $user->setFirstName('W');
        $user->setLastName('T');
        $user->setPassword('h');
        $user->setTempPassword('temp123');
        $customer = new Customer($user);
        $ref = new \ReflectionProperty(Customer::class, 'id');
        $ref->setAccessible(true);
        $ref->setValue($customer, 5);

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

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));
        $controller = $this->createController($request);

        $response = $controller->resendWelcome($customer, $mailer, $twig);
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testResendWelcomeWithoutTempPassword(): void
    {
        $user = new User();
        $user->setEmail('w@t.com');
        $user->setFirstName('W');
        $user->setLastName('T');
        $user->setPassword('h');
        // No temp password set
        $customer = new Customer($user);
        $ref = new \ReflectionProperty(Customer::class, 'id');
        $ref->setAccessible(true);
        $ref->setValue($customer, 6);

        $mailer = $this->createStub(MailerService::class);
        $twig = $this->createStub(Environment::class);

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));
        $controller = $this->createController($request);

        $response = $controller->resendWelcome($customer, $mailer, $twig);
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostContacts(): void
    {
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);
        $entityRepo->method('find')->willReturn(null);

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);
        $em->expects($this->atLeastOnce())->method('flush');
        $em->method('persist');

        $request = new Request(['tab' => 'contacts'], [
            'contact_action' => 'create',
            'contact_firstName' => 'Jean',
            'contact_lastName' => 'Dupont',
            'contact_email' => 'jean@test.com',
            'contact_phone' => '0600000000',
            'contact_role' => 'Directeur',
            'contact_isBilling' => '1',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostContactsDeleteAction(): void
    {
        $customer = $this->buildCustomer();

        $contact = $this->createStub(\App\Entity\CustomerContact::class);
        $contact->method('getCustomer')->willReturn($customer);

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('find')->willReturnMap([[99, null, null, $contact]]);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);
        $em->expects($this->once())->method('remove');
        $em->expects($this->once())->method('flush');

        $request = new Request(['tab' => 'contacts'], [
            'contact_action' => 'delete',
            'contact_id' => '99',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostNddCreateDomain(): void
    {
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null); // domain does not exist yet
        $entityRepo->method('find')->willReturn(null);

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);
        $em->expects($this->atLeastOnce())->method('flush');
        $em->method('persist');

        $ovh = $this->createStub(\App\Service\OvhService::class);
        $ovh->method('isDomainManaged')->willReturn(false);

        $cloudflare = $this->createStub(\App\Service\CloudflareService::class);
        $cloudflare->method('isAvailable')->willReturn(false);

        $dnsCheck = $this->createStub(\App\Service\DnsCheckService::class);
        $dnsCheck->method('getExpirationDate')->willReturn(null);

        $request = new Request(['tab' => 'ndd'], [
            'domain_action' => 'create',
            'domain_fqdn' => 'example.fr',
            'domain_registrar' => 'OVH',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $ovh,
            $cloudflare,
            $dnsCheck,
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostNddCreateDomainAlreadyExists(): void
    {
        $customer = $this->buildCustomer();

        $existingDomain = $this->createStub(\App\Entity\Domain::class);
        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findOneBy')->willReturn($existingDomain); // domain already exists
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);

        $em = $this->createStub(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);

        $request = new Request(['tab' => 'ndd'], [
            'domain_action' => 'create',
            'domain_fqdn' => 'existing.fr',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostNddCreateDomainEmptyFqdn(): void
    {
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);

        $em = $this->createStub(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);

        $request = new Request(['tab' => 'ndd'], [
            'domain_action' => 'create',
            'domain_fqdn' => '', // empty FQDN
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostNddDeleteDomain(): void
    {
        $customer = $this->buildCustomer();

        $domain = $this->createStub(\App\Entity\Domain::class);
        $domain->method('getCustomer')->willReturn($customer);

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('find')->willReturnMap([[5, null, null, $domain]]);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);
        $em->expects($this->once())->method('remove');
        $em->expects($this->once())->method('flush');

        $request = new Request(['tab' => 'ndd'], [
            'domain_action' => 'delete',
            'domain_id' => '5',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostSecuriteSendResetPassword(): void
    {
        $customer = $this->buildCustomer();
        $user = $customer->getUser();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);

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

        $passwordHasher = $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class);
        $passwordHasher->method('hashPassword')->willReturn('hashed_pw');

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

        $request = new Request(['tab' => 'securite'], [
            'security_action' => 'send_reset_password',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $passwordHasher,
            $this->createStub(MailerService::class),
            $twig,
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostSecuriteDisable2fa(): void
    {
        $customer = $this->buildCustomer();
        $user = $customer->getUser();
        $user->setIsEmailAuthEnabled(true);

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);

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

        $request = new Request(['tab' => 'securite'], [
            'security_action' => 'disable_2fa',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
        $this->assertFalse($user->isEmailAuthEnabled());
    }

    public function testShowGetNddTabWithDnsCheck(): void
    {
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);
        $entityRepo->method('find')->willReturn(null);

        $em = $this->createStub(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);

        $esyMailService = $this->createStub(\App\Service\EsyMailDnsService::class);
        $esyMailService->method('checkDnsEsyMail')->willReturn(['ok' => true]);
        $esyMailService->method('checkDnsEsyMailer')->willReturn(['ok' => false]);

        $request = new Request(['tab' => 'ndd']);
        $request->setMethod('GET');

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $esyMailService,
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertInstanceOf(Response::class, $response);
    }

    // ---------------------------------------------------------------
    // autoDetectDomain — OVH managed path
    // ---------------------------------------------------------------

    public function testShowPostNddCreateDomainOvhManaged(): void
    {
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);
        $entityRepo->method('find')->willReturn(null);

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);
        $em->expects($this->atLeastOnce())->method('flush');
        $em->method('persist');

        $ovh = $this->createStub(\App\Service\OvhService::class);
        $ovh->method('isDomainManaged')->willReturn(true);
        $ovh->method('getDomainServiceInfo')->willReturn([
            'expiration' => '2027-04-01',
            'creation' => '2024-04-01',
        ]);
        $ovh->method('getZoneInfo')->willReturn(['nameServers' => []]);

        $cloudflare = $this->createStub(\App\Service\CloudflareService::class);
        $cloudflare->method('isAvailable')->willReturn(false);

        $dnsCheck = $this->createStub(\App\Service\DnsCheckService::class);
        $dnsCheck->method('getExpirationDate')->willReturn(null);

        $request = new Request(['tab' => 'ndd'], [
            'domain_action' => 'create',
            'domain_fqdn' => 'ovh-managed.fr',
            'domain_registrar' => '',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $ovh,
            $cloudflare,
            $dnsCheck,
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostNddCreateDomainCloudflareAvailable(): void
    {
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);
        $entityRepo->method('find')->willReturn(null);

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);
        $em->expects($this->atLeastOnce())->method('flush');
        $em->method('persist');

        $ovh = $this->createStub(\App\Service\OvhService::class);
        $ovh->method('isDomainManaged')->willReturn(false);

        $cloudflare = $this->createStub(\App\Service\CloudflareService::class);
        $cloudflare->method('isAvailable')->willReturn(true);
        $cloudflare->method('getZoneId')->willReturn('zone123abc');

        $dnsCheck = $this->createStub(\App\Service\DnsCheckService::class);
        $dnsCheck->method('getExpirationDate')->willReturn(null);

        $request = new Request(['tab' => 'ndd'], [
            'domain_action' => 'create',
            'domain_fqdn' => 'cloudflare-domain.fr',
            'domain_registrar' => '',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $ovh,
            $cloudflare,
            $dnsCheck,
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostNddCreateDomainWithExpirationFromDns(): void
    {
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);
        $entityRepo->method('find')->willReturn(null);

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);
        $em->expects($this->atLeastOnce())->method('flush');
        $em->method('persist');

        $ovh = $this->createStub(\App\Service\OvhService::class);
        $ovh->method('isDomainManaged')->willReturn(false);

        $cloudflare = $this->createStub(\App\Service\CloudflareService::class);
        $cloudflare->method('isAvailable')->willReturn(true);
        $cloudflare->method('getZoneId')->willReturn(null);

        $dnsCheck = $this->createStub(\App\Service\DnsCheckService::class);
        $dnsCheck->method('getExpirationDate')->willReturn(new \DateTimeImmutable('2028-01-01'));

        $request = new Request(['tab' => 'ndd'], [
            'domain_action' => 'create',
            'domain_fqdn' => 'expiration-from-rdap.fr',
            'domain_registrar' => '',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $ovh,
            $cloudflare,
            $dnsCheck,
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    // ---------------------------------------------------------------
    // buildDomainsInfo — with actual domain having emails (esyMail=true)
    // ---------------------------------------------------------------

    public function testShowGetWithDomainHavingEmails(): void
    {
        $customer = $this->buildCustomer();

        $domain = $this->createStub(\App\Entity\Domain::class);
        $domain->method('getId')->willReturn(10);
        $domain->method('getFqdn')->willReturn('test-domain.fr');

        $domainEmailRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $domainEmailRepo->method('count')->willReturn(3);
        $domainEmailRepo->method('findBy')->willReturn([]);

        $websiteRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $websiteRepo->method('count')->willReturn(0);
        $websiteRepo->method('findBy')->willReturn([]);

        $contactRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $contactRepo->method('findBy')->willReturn([]);
        $contactRepo->method('count')->willReturn(0);
        $contactRepo->method('findOneBy')->willReturn(null);

        $domainRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $domainRepo->method('findBy')->willReturn([$domain]);
        $domainRepo->method('findOneBy')->willReturn(null);

        $devisRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $devisRepo->method('findBy')->willReturn([]);

        $advertRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $advertRepo->method('findBy')->willReturn([]);

        $factureRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $factureRepo->method('findBy')->willReturn([]);

        $em = $this->createStub(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturnCallback(function (string $entity) use (
            $contactRepo, $domainRepo, $domainEmailRepo, $websiteRepo, $devisRepo, $advertRepo, $factureRepo
        ) {
            return match ($entity) {
                \App\Entity\CustomerContact::class => $contactRepo,
                \App\Entity\Domain::class => $domainRepo,
                \App\Entity\DomainEmail::class => $domainEmailRepo,
                \App\Entity\Website::class => $websiteRepo,
                \App\Entity\Devis::class => $devisRepo,
                \App\Entity\Advert::class => $advertRepo,
                \App\Entity\Facture::class => $factureRepo,
                default => $contactRepo,
            };
        });

        $esyMailService = $this->createStub(\App\Service\EsyMailDnsService::class);
        $esyMailService->method('checkDnsEsyMail')->willReturn(['ok' => true]);
        $esyMailService->method('checkDnsEsyMailer')->willReturn(['ok' => false]);

        $request = new Request(['tab' => 'ndd']);
        $request->setMethod('GET');

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $esyMailService,
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertInstanceOf(Response::class, $response);
    }

    // ---------------------------------------------------------------
    // create POST — codeComptable already starts with EC- prefix
    // ---------------------------------------------------------------

    public function testCreatePostWithEcPrefixCodeComptable(): void
    {
        $user = new User();
        $user->setEmail('ec@test.com');
        $user->setFirstName('EC');
        $user->setLastName('Test');
        $user->setPassword('h');

        $userService = $this->createStub(UserManagementService::class);
        $userService->method('createBaseUser')->willReturn($user);

        $repo = $this->createStub(CustomerRepository::class);
        // generateUniqueCodeComptable should NOT be called because codeComptable is provided

        $request = new Request([], [
            'firstName' => 'EC', 'lastName' => 'Test', 'email' => 'ec@test.com',
            'phone' => '', 'raisonSociale' => '', 'siret' => '', 'rcs' => '',
            'numTva' => '', 'address' => '', 'address2' => '', 'zipCode' => '',
            'city' => '', 'typeCompany' => '',
            'codeComptable' => 'EC-12345', // already starts with EC-
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->create(
            $request,
            $repo,
            $this->createStub(\App\Repository\RevendeurRepository::class),
            $this->createStub(EntityManagerInterface::class),
            $this->createStub(MeilisearchService::class),
            $userService,
            $this->createStub(LoggerInterface::class),
            $this->createStub(HttpClientInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            '',
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    // ---------------------------------------------------------------
    // show GET — ensureDefaultContact returns early when contacts exist
    // ---------------------------------------------------------------

    public function testShowGetWithExistingContacts(): void
    {
        $customer = $this->buildCustomer();

        $existingContact = $this->createStub(\App\Entity\CustomerContact::class);

        $contactRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $contactRepo->method('findBy')->willReturn([$existingContact]); // contacts already exist → early return
        $contactRepo->method('count')->willReturn(0);
        $contactRepo->method('findOneBy')->willReturn(null);
        $contactRepo->method('find')->willReturn(null);

        $otherRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $otherRepo->method('findBy')->willReturn([]);
        $otherRepo->method('count')->willReturn(0);
        $otherRepo->method('findOneBy')->willReturn(null);
        $otherRepo->method('find')->willReturn(null);

        $em = $this->createStub(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturnCallback(function (string $entity) use ($contactRepo, $otherRepo) {
            return \App\Entity\CustomerContact::class === $entity ? $contactRepo : $otherRepo;
        });

        $request = new Request(['tab' => 'info']);
        $request->setMethod('GET');

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertInstanceOf(Response::class, $response);
    }

    public function testCreatePostMeilisearchError(): void
    {
        $user = new User();
        $user->setEmail('c@d.com');
        $user->setFirstName('C');
        $user->setLastName('D');
        $user->setPassword('h');

        $userService = $this->createStub(UserManagementService::class);
        $userService->method('createBaseUser')->willReturn($user);

        $repo = $this->createStub(CustomerRepository::class);
        $repo->method('generateUniqueCodeComptable')->willReturn('CLI-00003');

        $meilisearch = $this->createStub(MeilisearchService::class);
        $meilisearch->method('indexCustomer')->willThrowException(new \RuntimeException('Meili down'));

        $request = new Request([], [
            'firstName' => 'C', 'lastName' => 'D', 'email' => 'c@d.com',
            'phone' => '', 'raisonSociale' => '', 'siret' => '', 'rcs' => '',
            'numTva' => '', 'address' => '', 'address2' => '', 'zipCode' => '',
            'city' => '', 'typeCompany' => '',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->create(
            $request,
            $repo,
            $this->createStub(\App\Repository\RevendeurRepository::class),
            $this->createStub(EntityManagerInterface::class),
            $meilisearch,
            $userService,
            $this->createStub(LoggerInterface::class),
            $this->createStub(HttpClientInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            '',
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testShowPostContactsCreateWithEmptyNames(): void
    {
        // Covers the persistNewContact early-return branch when firstName or lastName is empty
        $customer = $this->buildCustomer();

        $entityRepo = $this->createStub(\Doctrine\ORM\EntityRepository::class);
        $entityRepo->method('findBy')->willReturn([]);
        $entityRepo->method('count')->willReturn(0);
        $entityRepo->method('findOneBy')->willReturn(null);
        $entityRepo->method('find')->willReturn(null);

        $em = $this->createMock(\Doctrine\ORM\EntityManagerInterface::class);
        $em->method('getRepository')->willReturn($entityRepo);
        // flush should NOT be called because persistNewContact returns early
        $em->expects($this->never())->method('flush');

        $request = new Request(['tab' => 'contacts'], [
            'contact_action' => 'create',
            'contact_firstName' => '',  // empty -> early return
            'contact_lastName' => 'Dupont',
        ]);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));

        $controller = $this->createController($request);

        $response = $controller->show(
            $customer,
            $request,
            $em,
            $this->createStub(\App\Service\OvhService::class),
            $this->createStub(\App\Service\CloudflareService::class),
            $this->createStub(\App\Service\DnsCheckService::class),
            $this->createStub(\App\Service\EsyMailDnsService::class),
            $this->createStub(\Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
        );
        $this->assertSame(302, $response->getStatusCode());
    }
}
