<?php

namespace App\Tests\Controller;

use App\Controller\FactureVerifyController;
use App\Entity\Customer;
use App\Entity\Facture;
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\Response;
use Twig\Environment;

class FactureVerifyControllerTest extends TestCase
{
    private function buildController(?Environment $twig = null): FactureVerifyController
    {
        $twig ??= $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');

        $container = $this->createStub(ContainerInterface::class);
        $container->method('has')->willReturnMap([
            ['twig', true],
            ['parameter_bag', true],
        ]);
        $container->method('get')->willReturnMap([
            ['twig', $twig],
            ['parameter_bag', $this->createStub(ParameterBagInterface::class)],
        ]);

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

        return $controller;
    }

    private function buildEmWithFacture(?Facture $facture): EntityManagerInterface
    {
        $factureRepo = $this->createStub(EntityRepository::class);
        $factureRepo->method('find')->willReturn($facture);

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

        return $em;
    }

    // ---------------------------------------------------------------
    // Valid HMAC — facture found with correct hmac
    // ---------------------------------------------------------------

    public function testIndexReturnsVerifyPageWhenHmacMatches(): void
    {
        $customer = $this->createStub(Customer::class);

        $facture = $this->createStub(Facture::class);
        $facture->method('getHmac')->willReturn('abc123');
        $facture->method('getCustomer')->willReturn($customer);

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

        $response = $controller->index(1, 'abc123', $em);

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

    // ---------------------------------------------------------------
    // Invalid HMAC — facture found but wrong hmac
    // ---------------------------------------------------------------

    public function testIndexReturnsInvalidPageWhenHmacMismatch(): void
    {
        $facture = $this->createStub(Facture::class);
        $facture->method('getHmac')->willReturn('correct_hmac');

        $em = $this->buildEmWithFacture($facture);

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

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

        $response = $controller->index(1, 'wrong_hmac', $em);

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

    // ---------------------------------------------------------------
    // Facture not found
    // ---------------------------------------------------------------

    public function testIndexReturnsInvalidPageWhenFactureNotFound(): void
    {
        $em = $this->buildEmWithFacture(null);
        $controller = $this->buildController();

        $response = $controller->index(999, 'any_hmac', $em);

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

    // ---------------------------------------------------------------
    // HMAC timing-safe comparison (hash_equals)
    // ---------------------------------------------------------------

    public function testIndexUsesHashEqualsForComparison(): void
    {
        // Craft two hmac values that differ only in length to ensure no
        // trivial == comparison is used (hash_equals handles timing safety)
        $storedHmac = hash_hmac('sha256', 'data', 'secret');
        $differentHmac = hash_hmac('sha256', 'other', 'secret');

        $facture = $this->createStub(Facture::class);
        $facture->method('getHmac')->willReturn($storedHmac);

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

        // Wrong hmac -> invalid page (still 200 but renders invalid template)
        $response = $controller->index(1, $differentHmac, $em);
        $this->assertSame(200, $response->getStatusCode());

        // Correct hmac -> verify page
        $facture2 = $this->createStub(Facture::class);
        $facture2->method('getHmac')->willReturn($storedHmac);
        $facture2->method('getCustomer')->willReturn(null);

        $em2 = $this->buildEmWithFacture($facture2);
        $response2 = $controller->index(1, $storedHmac, $em2);
        $this->assertSame(200, $response2->getStatusCode());
    }
}
