<?php

namespace App\Tests\Controller;

use App\Controller\AttestationController;
use App\Entity\Attestation;
use App\Repository\AttestationRepository;
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\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Twig\Environment;

class AttestationControllerTest extends TestCase
{
    private const HMAC_SECRET = 'test-hmac-secret';

    private function setupController(AttestationController $controller): void
    {
        $session = new Session(new MockArraySessionStorage());
        $stack = $this->createStub(RequestStack::class);
        $stack->method('getSession')->willReturn($session);

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

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

        $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)],
        ]);
        $controller->setContainer($container);
    }

    public function testVerifyNotFound(): void
    {
        $repo = $this->createStub(AttestationRepository::class);
        $repo->method('findOneBy')->willReturn(null);

        $controller = new AttestationController();
        $this->setupController($controller);

        $response = $controller->verify('REF-UNKNOWN', $repo, self::HMAC_SECRET);
        $this->assertSame(200, $response->getStatusCode());
    }

    public function testVerifyFound(): void
    {
        $attestation = new Attestation('access', '127.0.0.1', 'test@test.com', self::HMAC_SECRET);

        $repo = $this->createStub(AttestationRepository::class);
        $repo->method('findOneBy')->willReturn($attestation);

        $controller = new AttestationController();
        $this->setupController($controller);

        $response = $controller->verify($attestation->getReference(), $repo, self::HMAC_SECRET);
        $this->assertSame(200, $response->getStatusCode());
    }

    public function testDownloadNotFound(): void
    {
        $repo = $this->createStub(AttestationRepository::class);
        $repo->method('findOneBy')->willReturn(null);

        $controller = new AttestationController();
        $this->setupController($controller);

        $this->expectException(NotFoundHttpException::class);
        $controller->download('REF-UNKNOWN', $repo);
    }

    public function testDownloadNoPdf(): void
    {
        $attestation = new Attestation('access', '127.0.0.1', 'test@test.com', self::HMAC_SECRET);

        $repo = $this->createStub(AttestationRepository::class);
        $repo->method('findOneBy')->willReturn($attestation);

        $controller = new AttestationController();
        $this->setupController($controller);

        $this->expectException(NotFoundHttpException::class);
        $controller->download($attestation->getReference(), $repo);
    }

    public function testDownloadWithPdf(): void
    {
        $attestation = new Attestation('access', '127.0.0.1', 'test@test.com', self::HMAC_SECRET);
        $tmpFile = tempnam(sys_get_temp_dir(), 'att_test_');
        file_put_contents($tmpFile, '%PDF-test');
        $attestation->setPdfFileSigned($tmpFile);

        $repo = $this->createStub(AttestationRepository::class);
        $repo->method('findOneBy')->willReturn($attestation);

        $controller = new AttestationController();
        $this->setupController($controller);

        $response = $controller->download($attestation->getReference(), $repo);
        $this->assertSame(200, $response->getStatusCode());

        @unlink($tmpFile);
    }

    public function testAuditNotFound(): void
    {
        $repo = $this->createStub(AttestationRepository::class);
        $repo->method('findOneBy')->willReturn(null);

        $controller = new AttestationController();
        $this->setupController($controller);

        $this->expectException(NotFoundHttpException::class);
        $controller->audit('REF-UNKNOWN', $repo);
    }

    public function testAuditNoCertificate(): void
    {
        $attestation = new Attestation('deletion', '127.0.0.1', 'test@test.com', self::HMAC_SECRET);

        $repo = $this->createStub(AttestationRepository::class);
        $repo->method('findOneBy')->willReturn($attestation);

        $controller = new AttestationController();
        $this->setupController($controller);

        $this->expectException(NotFoundHttpException::class);
        $controller->audit($attestation->getReference(), $repo);
    }

    public function testAuditWithCertificate(): void
    {
        $attestation = new Attestation('deletion', '127.0.0.1', 'test@test.com', self::HMAC_SECRET);
        $tmpFile = tempnam(sys_get_temp_dir(), 'cert_test_');
        file_put_contents($tmpFile, '%PDF-cert');
        $attestation->setPdfFileCertificate($tmpFile);

        $repo = $this->createStub(AttestationRepository::class);
        $repo->method('findOneBy')->willReturn($attestation);

        $controller = new AttestationController();
        $this->setupController($controller);

        $response = $controller->audit($attestation->getReference(), $repo);
        $this->assertSame(200, $response->getStatusCode());

        @unlink($tmpFile);
    }
}
