<?php

declare(strict_types=1);

namespace App\Tests\Unit\Shared\Infrastructure\Tenant;

use App\Shared\Infrastructure\Tenant\TenantConfig;
use App\Shared\Infrastructure\Tenant\TenantDatabaseRequestSubscriber;
use App\Shared\Infrastructure\Tenant\TenantDatabaseSwitcher;
use App\Shared\Infrastructure\Tenant\TenantId;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;

#[CoversClass(TenantDatabaseRequestSubscriber::class)]
final class TenantDatabaseRequestSubscriberTest extends TestCase
{
    #[Test]
    public function itUsesTheTenantDatabaseResolvedByTheMiddleware(): void
    {
        $tenantConfig = new TenantConfig(
            tenantId: TenantId::fromString('a1b2c3d4-e5f6-7890-abcd-ef1234567890'),
            subdomain: 'ecole-alpha',
            databaseUrl: 'postgresql://tenant:secret@db:5432/classeo_tenant_alpha?serverVersion=18&charset=utf8',
        );

        $databaseSwitcher = $this->createMock(TenantDatabaseSwitcher::class);
        $databaseSwitcher->expects(self::once())
            ->method('useTenantDatabase')
            ->with($tenantConfig->databaseUrl);

        $subscriber = new TenantDatabaseRequestSubscriber($databaseSwitcher);
        $request = Request::create('https://ecole-alpha.classeo.local/api/users');
        $request->attributes->set('_tenant', $tenantConfig);

        $subscriber->onKernelRequest($this->createRequestEvent($request));
    }

    #[Test]
    public function itFallsBackToTheDefaultDatabaseWhenNoTenantWasResolved(): void
    {
        $databaseSwitcher = $this->createMock(TenantDatabaseSwitcher::class);
        $databaseSwitcher->expects(self::once())
            ->method('useDefaultDatabase');

        $subscriber = new TenantDatabaseRequestSubscriber($databaseSwitcher);
        $request = Request::create('https://classeo.local/api/docs');

        $subscriber->onKernelRequest($this->createRequestEvent($request));
    }

    #[Test]
    public function itResetsTheConnectionAfterTheRequest(): void
    {
        $databaseSwitcher = $this->createMock(TenantDatabaseSwitcher::class);
        $databaseSwitcher->expects(self::once())
            ->method('useDefaultDatabase');

        $subscriber = new TenantDatabaseRequestSubscriber($databaseSwitcher);
        $subscriber->onKernelTerminate();
    }

    #[Test]
    public function itRegistersItselfRightAfterTenantResolution(): void
    {
        $events = TenantDatabaseRequestSubscriber::getSubscribedEvents();

        self::assertSame(['onKernelRequest', 255], $events[KernelEvents::REQUEST]);
        self::assertSame('onKernelTerminate', $events[KernelEvents::TERMINATE]);
    }

    private function createRequestEvent(Request $request): RequestEvent
    {
        $kernel = $this->createMock(HttpKernelInterface::class);

        return new RequestEvent(
            $kernel,
            $request,
            HttpKernelInterface::MAIN_REQUEST,
        );
    }
}
