<?php

namespace App\Tests\Controller;

use App\Controller\DevisPdfController;
use App\Entity\Devis;
use App\Entity\OrderNumber;
use App\Repository\DevisRepository;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

class DevisPdfControllerTest extends TestCase
{
    private function createContainer(bool $isEmploye = true): ContainerInterface
    {
        $session = new Session(new MockArraySessionStorage());
        $stack = $this->createStub(RequestStack::class);
        $stack->method('getSession')->willReturn($session);

        $authChecker = $this->createStub(AuthorizationCheckerInterface::class);
        $authChecker->method('isGranted')->willReturn($isEmploye);

        $container = $this->createStub(ContainerInterface::class);
        $container->method('has')->willReturn(true);
        $container->method('get')->willReturnMap([
            ['router', $this->createStub(RouterInterface::class)],
            ['security.authorization_checker', $authChecker],
            ['security.token_storage', $this->createStub(TokenStorageInterface::class)],
            ['request_stack', $stack],
            ['parameter_bag', $this->createStub(\Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface::class)],
        ]);

        return $container;
    }

    public function testDevisNotFound(): void
    {
        $repo = $this->createStub(DevisRepository::class);
        $repo->method('find')->willReturn(null);

        $controller = new DevisPdfController($this->createStub(\Psr\Log\LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $this->expectException(NotFoundHttpException::class);
        $controller(1, 'unsigned', $repo, '/tmp');
    }

    public function testUnsignedPdfNotSet(): void
    {
        $devis = new Devis(new OrderNumber('04/2026-00001'), 'secret');

        $repo = $this->createStub(DevisRepository::class);
        $repo->method('find')->willReturn($devis);

        $controller = new DevisPdfController($this->createStub(\Psr\Log\LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $this->expectException(NotFoundHttpException::class);
        $controller(1, 'unsigned', $repo, '/tmp');
    }

    public function testFileNotExists(): void
    {
        $devis = new Devis(new OrderNumber('04/2026-00002'), 'secret');
        $devis->setUnsignedPdf('nonexistent.pdf');

        $repo = $this->createStub(DevisRepository::class);
        $repo->method('find')->willReturn($devis);

        $controller = new DevisPdfController($this->createStub(\Psr\Log\LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $this->expectException(NotFoundHttpException::class);
        $controller(1, 'unsigned', $repo, '/tmp');
    }

    public function testUnsignedPdfSuccess(): void
    {
        $tmpDir = sys_get_temp_dir().'/devis_test_'.uniqid();
        mkdir($tmpDir.'/public/uploads/devis', 0775, true);
        file_put_contents($tmpDir.'/public/uploads/devis/test.pdf', '%PDF-test');

        $devis = new Devis(new OrderNumber('042026-00003'), 'secret');
        $devis->setUnsignedPdf('test.pdf');

        $repo = $this->createStub(DevisRepository::class);
        $repo->method('find')->willReturn($devis);

        $controller = new DevisPdfController($this->createStub(\Psr\Log\LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller(1, 'unsigned', $repo, $tmpDir);
        $this->assertSame(200, $response->getStatusCode());

        @unlink($tmpDir.'/public/uploads/devis/test.pdf');
        @rmdir($tmpDir.'/public/uploads/devis');
        @rmdir($tmpDir.'/public/uploads');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);
    }

    public function testSignedPdfSuccess(): void
    {
        $tmpDir = sys_get_temp_dir().'/devis_test_'.uniqid();
        mkdir($tmpDir.'/public/uploads/devis', 0775, true);
        file_put_contents($tmpDir.'/public/uploads/devis/signed.pdf', '%PDF');

        $devis = new Devis(new OrderNumber('042026-00004'), 'secret');
        $devis->setSignedPdf('signed.pdf');

        $repo = $this->createStub(DevisRepository::class);
        $repo->method('find')->willReturn($devis);

        $controller = new DevisPdfController($this->createStub(\Psr\Log\LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller(1, 'signed', $repo, $tmpDir);
        $this->assertSame(200, $response->getStatusCode());

        @unlink($tmpDir.'/public/uploads/devis/signed.pdf');
        @rmdir($tmpDir.'/public/uploads/devis');
        @rmdir($tmpDir.'/public/uploads');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);
    }

    public function testAuditPdfSuccess(): void
    {
        $tmpDir = sys_get_temp_dir().'/devis_test_'.uniqid();
        mkdir($tmpDir.'/public/uploads/devis', 0775, true);
        file_put_contents($tmpDir.'/public/uploads/devis/audit.pdf', '%PDF');

        $devis = new Devis(new OrderNumber('042026-00005'), 'secret');
        $devis->setAuditPdf('audit.pdf');

        $repo = $this->createStub(DevisRepository::class);
        $repo->method('find')->willReturn($devis);

        $controller = new DevisPdfController($this->createStub(\Psr\Log\LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $response = $controller(1, 'audit', $repo, $tmpDir);
        $this->assertSame(200, $response->getStatusCode());

        @unlink($tmpDir.'/public/uploads/devis/audit.pdf');
        @rmdir($tmpDir.'/public/uploads/devis');
        @rmdir($tmpDir.'/public/uploads');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);
    }

    public function testAccessAsNonEmploye(): void
    {
        $tmpDir = sys_get_temp_dir().'/devis_test_'.uniqid();
        mkdir($tmpDir.'/public/uploads/devis', 0775, true);
        file_put_contents($tmpDir.'/public/uploads/devis/test.pdf', '%PDF');

        $devis = new Devis(new OrderNumber('042026-00006'), 'secret');
        $devis->setUnsignedPdf('test.pdf');

        $repo = $this->createStub(DevisRepository::class);
        $repo->method('find')->willReturn($devis);

        $controller = new DevisPdfController($this->createStub(\Psr\Log\LoggerInterface::class));
        $controller->setContainer($this->createContainer(false));

        $response = $controller(1, 'unsigned', $repo, $tmpDir);
        $this->assertSame(200, $response->getStatusCode());

        @unlink($tmpDir.'/public/uploads/devis/test.pdf');
        @rmdir($tmpDir.'/public/uploads/devis');
        @rmdir($tmpDir.'/public/uploads');
        @rmdir($tmpDir.'/public');
        @rmdir($tmpDir);
    }

    public function testDefaultTypeNull(): void
    {
        $devis = new Devis(new OrderNumber('04/2026-00007'), 'secret');

        $repo = $this->createStub(DevisRepository::class);
        $repo->method('find')->willReturn($devis);

        $controller = new DevisPdfController($this->createStub(\Psr\Log\LoggerInterface::class));
        $controller->setContainer($this->createContainer());

        $this->expectException(NotFoundHttpException::class);
        $controller(1, 'unknown', $repo, '/tmp');
    }
}
