<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Infrastructure\Messaging;

use App\Administration\Domain\Event\CompteActive;
use App\Administration\Domain\Model\User\Role;
use App\Administration\Infrastructure\Messaging\SendActivationConfirmationHandler;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Ramsey\Uuid\Uuid;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Twig\Environment;

/**
 * Tests for SendActivationConfirmationHandler.
 *
 * Key invariants:
 * - Sends email to the activated user's address
 * - Uses the correct Twig template
 * - Login URL is constructed from appUrl
 * - Role label is resolved from Role enum
 */
final class SendActivationConfirmationHandlerTest extends TestCase
{
    private const string APP_URL = 'https://ecole-alpha.classeo.fr';
    private const string FROM_EMAIL = 'noreply@classeo.fr';

    private MailerInterface $mailer;
    private Environment $twig;

    protected function setUp(): void
    {
        $this->mailer = $this->createMock(MailerInterface::class);
        $this->twig = $this->createMock(Environment::class);
    }

    #[Test]
    public function sendsEmailToActivatedUser(): void
    {
        $event = $this->createEvent('user@example.com', Role::PROF->value);

        $this->twig->method('render')->willReturn('<p>Votre compte est actif.</p>');

        $sentEmail = null;
        $this->mailer->expects(self::once())
            ->method('send')
            ->with(self::callback(static function (Email $email) use (&$sentEmail): bool {
                $sentEmail = $email;

                return true;
            }));

        $handler = new SendActivationConfirmationHandler(
            $this->mailer,
            $this->twig,
            self::APP_URL,
            self::FROM_EMAIL,
        );

        ($handler)($event);

        self::assertNotNull($sentEmail);
        self::assertSame('user@example.com', $sentEmail->getTo()[0]->getAddress());
        self::assertSame(self::FROM_EMAIL, $sentEmail->getFrom()[0]->getAddress());
        self::assertSame('Votre compte Classeo est activé', $sentEmail->getSubject());
    }

    #[Test]
    public function rendersTemplateWithCorrectVariables(): void
    {
        $event = $this->createEvent('teacher@example.com', Role::PROF->value);

        $this->twig->expects(self::once())
            ->method('render')
            ->with(
                'emails/activation_confirmation.html.twig',
                self::callback(static function (array $vars): bool {
                    return $vars['email'] === 'teacher@example.com'
                        && $vars['role'] === 'Enseignant'
                        && $vars['loginUrl'] === 'https://ecole-alpha.classeo.fr/login';
                }),
            )
            ->willReturn('<p>HTML</p>');

        $this->mailer->method('send');

        $handler = new SendActivationConfirmationHandler(
            $this->mailer,
            $this->twig,
            self::APP_URL,
            self::FROM_EMAIL,
        );

        ($handler)($event);
    }

    #[Test]
    public function handlesTrailingSlashInAppUrl(): void
    {
        $event = $this->createEvent('user@example.com', Role::PARENT->value);

        $this->twig->expects(self::once())
            ->method('render')
            ->with(
                self::anything(),
                self::callback(static function (array $vars): bool {
                    // Should not have double slash
                    return $vars['loginUrl'] === 'https://ecole-alpha.classeo.fr/login';
                }),
            )
            ->willReturn('<p>HTML</p>');

        $this->mailer->method('send');

        $handler = new SendActivationConfirmationHandler(
            $this->mailer,
            $this->twig,
            'https://ecole-alpha.classeo.fr/',
            self::FROM_EMAIL,
        );

        ($handler)($event);
    }

    #[Test]
    public function usesRoleLabelForKnownRoles(): void
    {
        $event = $this->createEvent('admin@example.com', Role::ADMIN->value);

        $this->twig->expects(self::once())
            ->method('render')
            ->with(
                self::anything(),
                self::callback(static function (array $vars): bool {
                    return $vars['role'] === 'Directeur';
                }),
            )
            ->willReturn('<p>HTML</p>');

        $this->mailer->method('send');

        $handler = new SendActivationConfirmationHandler(
            $this->mailer,
            $this->twig,
            self::APP_URL,
            self::FROM_EMAIL,
        );

        ($handler)($event);
    }

    #[Test]
    public function fallsBackToRawStringForUnknownRole(): void
    {
        $event = $this->createEvent('user@example.com', 'ROLE_CUSTOM');

        $this->twig->expects(self::once())
            ->method('render')
            ->with(
                self::anything(),
                self::callback(static function (array $vars): bool {
                    return $vars['role'] === 'ROLE_CUSTOM';
                }),
            )
            ->willReturn('<p>HTML</p>');

        $this->mailer->method('send');

        $handler = new SendActivationConfirmationHandler(
            $this->mailer,
            $this->twig,
            self::APP_URL,
            self::FROM_EMAIL,
        );

        ($handler)($event);
    }

    private function createEvent(string $email, string $role): CompteActive
    {
        return new CompteActive(
            userId: '550e8400-e29b-41d4-a716-446655440001',
            email: $email,
            tenantId: TenantId::fromString('a1b2c3d4-e5f6-7890-abcd-ef1234567890'),
            role: $role,
            occurredOn: new DateTimeImmutable('2026-02-15 10:00:00'),
            aggregateId: Uuid::uuid4(),
        );
    }
}
