<?php

namespace App\Tests\Controller\Admin;

use App\Controller\Admin\RevendeursController;
use App\Entity\Revendeur;
use App\Entity\User;
use App\Repository\RevendeurRepository;
use App\Service\MailerService;
use App\Service\MeilisearchService;
use App\Service\UserManagementService;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
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 RevendeursControllerTest extends TestCase
{
    private function createContainer(): ContainerInterface
    {
        $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('/admin/revendeurs');

        $container = $this->createStub(ContainerInterface::class);
        $container->method('has')->willReturn(true);
        $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(\Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface::class)],
        ]);

        return $container;
    }

    private function createRevendeur(): Revendeur
    {
        $user = new User();
        $user->setEmail('rev@test.com');
        $user->setFirstName('Jean');
        $user->setLastName('Dupont');
        $user->setPassword('h');

        return new Revendeur($user, 'REV-001');
    }

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

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->index($repo);
        $this->assertSame(200, $response->getStatusCode());
    }

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

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->create(
            $request,
            $this->createStub(RevendeurRepository::class),
            $this->createStub(EntityManagerInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $this->createStub(UserManagementService::class),
        );
        $this->assertSame(200, $response->getStatusCode());
    }

    public function testCreatePostSuccess(): void
    {
        $user = new User();
        $user->setEmail('new@test.com');
        $user->setFirstName('A');
        $user->setLastName('B');
        $user->setPassword('h');
        $user->setTempPassword('tmp123');

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

        $repo = $this->createStub(RevendeurRepository::class);
        $repo->method('generateUniqueCode')->willReturn('REV-999');

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

        $request = new Request([], [
            'firstName' => 'Jean',
            'lastName' => 'Dupont',
            'email' => 'new@test.com',
            'raisonSociale' => 'Ma Societe',
            'siret' => '12345678901234',
            'phone' => '0612345678',
            'address' => '1 rue Test',
            'zipCode' => '75001',
            'city' => 'Paris',
            'isUseStripe' => '1',
        ]);
        $request->setMethod('POST');

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->create(
            $request,
            $repo,
            $this->createStub(EntityManagerInterface::class),
            $this->createStub(MailerService::class),
            $twig,
            $userService,
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testCreatePostInvalidArgument(): void
    {
        $userService = $this->createStub(UserManagementService::class);
        $userService->method('createBaseUser')->willThrowException(new \InvalidArgumentException('Email requis'));

        $request = new Request([], ['firstName' => '', 'lastName' => '', 'email' => '', 'raisonSociale' => '', 'siret' => '', 'phone' => '', 'address' => '', 'zipCode' => '', 'city' => '']);
        $request->setMethod('POST');

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->create(
            $request,
            $this->createStub(RevendeurRepository::class),
            $this->createStub(EntityManagerInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $userService,
        );
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testCreatePostThrowable(): void
    {
        $userService = $this->createStub(UserManagementService::class);
        $userService->method('createBaseUser')->willThrowException(new \RuntimeException('DB error'));

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

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->create(
            $request,
            $this->createStub(RevendeurRepository::class),
            $this->createStub(EntityManagerInterface::class),
            $this->createStub(MailerService::class),
            $this->createStub(Environment::class),
            $userService,
        );
        $this->assertSame(302, $response->getStatusCode());
    }

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

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));

        $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('searchRevendeurs')->willReturn([['id' => 1, 'name' => 'Test']]);

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));

        $request = new Request(['q' => 'test']);
        $response = $controller->search($request, $meilisearch);
        $this->assertInstanceOf(JsonResponse::class, $response);
        $this->assertStringContainsString('Test', $response->getContent());
    }

    public function testToggle(): void
    {
        $revendeur = $this->createRevendeur();
        $this->assertTrue($revendeur->isActive());

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->toggle($revendeur, $this->createStub(EntityManagerInterface::class));
        $this->assertSame(302, $response->getStatusCode());
        $this->assertFalse($revendeur->isActive());
    }

    public function testEditGet(): void
    {
        $revendeur = $this->createRevendeur();

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

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->edit($revendeur, $request, $this->createStub(EntityManagerInterface::class), $this->createStub(MeilisearchService::class));
        $this->assertSame(200, $response->getStatusCode());
    }

    public function testEditPost(): void
    {
        $revendeur = $this->createRevendeur();

        $request = new Request([], [
            'raisonSociale' => 'Updated SA',
            'siret' => '99999999999999',
            'email' => 'updated@test.com',
            'phone' => '0699999999',
            'address' => '2 avenue Test',
            'zipCode' => '69001',
            'city' => 'Lyon',
            'isUseStripe' => '0',
        ]);
        $request->setMethod('POST');

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->edit($revendeur, $request, $this->createStub(EntityManagerInterface::class), $this->createStub(MeilisearchService::class));
        $this->assertSame(302, $response->getStatusCode());
        $this->assertSame('Updated SA', $revendeur->getRaisonSociale());
    }

    public function testEditPostMeilisearchError(): void
    {
        $revendeur = $this->createRevendeur();

        $request = new Request([], [
            'raisonSociale' => 'Test',
            'siret' => '',
            'email' => 'e@t.com',
            'phone' => '',
            'address' => '',
            'zipCode' => '',
            'city' => '',
            'isUseStripe' => '0',
        ]);
        $request->setMethod('POST');

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

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->edit($revendeur, $request, $this->createStub(EntityManagerInterface::class), $meilisearch);
        $this->assertSame(302, $response->getStatusCode());
    }

    public function testContrat(): void
    {
        $revendeur = $this->createRevendeur();

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

        $tmpDir = sys_get_temp_dir().'/rev_test_'.uniqid();
        mkdir($tmpDir.'/public', 0775, true);
        file_put_contents($tmpDir.'/public/logo_facture.png', 'fake-png');

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->contrat($revendeur, $twig, $tmpDir);
        $this->assertSame(200, $response->getStatusCode());
        $this->assertSame('application/pdf', $response->headers->get('Content-Type'));

        @unlink($tmpDir.'/public/logo_facture.png');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);
    }

    public function testContratNoLogo(): void
    {
        $revendeur = $this->createRevendeur();

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

        $controller = new RevendeursController($this->createStub(LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller->contrat($revendeur, $twig, '/nonexistent');
        $this->assertSame(200, $response->getStatusCode());
        $this->assertSame('application/pdf', $response->headers->get('Content-Type'));
    }
}
