<?php

namespace App\Tests\Security;

use App\Security\IntranetLocked;
use App\Service\Mailer\Mailer;
use App\Service\Signature\Client as SignatureClient;
use App\Service\Search\Client as SearchClient;
use App\Service\Stripe\Client as StripeClient;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\Cache\CacheInterface;
use Twig\Environment;

#[AllowMockObjectsWithoutExpectations]
class IntranetLockedTest extends TestCase
{
    private $twig;
    private $signatureClient;
    private $searchClient;
    private $stripeClient;
    private $mailer;
    private $cache;
    private $listener;

    protected function setUp(): void
    {
        $this->twig = $this->createMock(Environment::class);
        $this->signatureClient = $this->createMock(SignatureClient::class);
        $this->searchClient = $this->createMock(SearchClient::class);
        $this->stripeClient = $this->createMock(StripeClient::class);
        $this->mailer = $this->createMock(Mailer::class);
        $this->cache = $this->createMock(CacheInterface::class);

        // Configuration par défaut du mock de cache :
        // Il exécute immédiatement le callback passé en argument (le 2ème paramètre de get())
        $this->cache->method('get')->willReturnCallback(function ($key, $callback) {
            $item = $this->createMock(\Symfony\Contracts\Cache\ItemInterface::class);
            return $callback($item);
        });

        $this->listener = new IntranetLocked(
            $this->twig,
            $this->signatureClient,
            $this->searchClient,
            $this->stripeClient,
            $this->mailer,
            $this->cache
        );
    }

    public function testOnLockedWhenEnabled()
    {
        $_ENV['INTRANET_LOCK'] = 'true';
        $kernel = $this->createMock(HttpKernelInterface::class);
        $request = new Request();
        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);

        $this->twig->expects($this->once())->method('render')->with('security/locked.twig')->willReturn('Locked');

        $this->listener->onLocked($event);

        $response = $event->getResponse();
        $this->assertInstanceOf(Response::class, $response);
        $this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());

        unset($_ENV['INTRANET_LOCK']);
    }

    public function testOnControlAllServicesUp()
    {
        $kernel = $this->createMock(HttpKernelInterface::class);
        $request = new Request();
        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);

        $this->signatureClient->method('status')->willReturn(true);
        $this->searchClient->method('status')->willReturn(true);
        $this->stripeClient->method('status')->willReturn(true);

        $this->listener->onControl($event);

        $this->assertNull($event->getResponse());
    }

    public function testOnControlServiceDown()
    {
        $kernel = $this->createMock(HttpKernelInterface::class);
        $request = new Request();
        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);

        // Simulation d'une panne
        $this->signatureClient->method('status')->willReturn(false);

        $this->mailer->expects($this->once())->method('send');
        $this->twig->expects($this->once())
            ->method('render')
            ->with('security/error.twig', $this->callback(function($subject) {
                return $subject['message']['service'] === 'Signature';
            }))
            ->willReturn('Error');

        $this->listener->onControl($event);

        $response = $event->getResponse();
        $this->assertNotNull($response);
        $this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
    }
}
