<?php

declare(strict_types=1);

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

use App\Administration\Domain\Event\JourneePedagogiqueAjoutee;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryId;
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
use App\Administration\Domain\Model\User\Email;
use App\Administration\Domain\Model\User\Role;
use App\Administration\Domain\Model\User\StatutCompte;
use App\Administration\Domain\Model\User\User;
use App\Administration\Domain\Model\User\UserId;
use App\Administration\Domain\Repository\UserRepository;
use App\Administration\Infrastructure\Messaging\NotifyTeachersPedagogicalDayHandler;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger;
use RuntimeException;
use Symfony\Component\Mailer\MailerInterface;
use Twig\Environment;

final class NotifyTeachersPedagogicalDayHandlerTest extends TestCase
{
    private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
    private const string ACADEMIC_YEAR_ID = '550e8400-e29b-41d4-a716-446655440010';

    #[Test]
    public function itSendsEmailToAllTeachersInTenant(): void
    {
        $mailer = $this->createMock(MailerInterface::class);
        $twig = $this->createMock(Environment::class);
        $userRepository = $this->createMock(UserRepository::class);

        $twig->method('render')->willReturn('<html>notification</html>');

        $userRepository->method('findAllByTenant')->willReturn([
            $this->createUser('teacher1@school.fr', [Role::PROF]),
            $this->createUser('teacher2@school.fr', [Role::PROF]),
            $this->createUser('parent@school.fr', [Role::PARENT]),
        ]);

        $mailer->expects(self::exactly(2))->method('send');

        $handler = new NotifyTeachersPedagogicalDayHandler($mailer, $twig, $userRepository, new NullLogger());
        ($handler)($this->createEvent());
    }

    #[Test]
    public function itSkipsWhenNoTeachersInTenant(): void
    {
        $mailer = $this->createMock(MailerInterface::class);
        $twig = $this->createMock(Environment::class);
        $userRepository = $this->createMock(UserRepository::class);

        $userRepository->method('findAllByTenant')->willReturn([
            $this->createUser('parent@school.fr', [Role::PARENT]),
        ]);

        $mailer->expects(self::never())->method('send');
        $twig->expects(self::never())->method('render');

        $handler = new NotifyTeachersPedagogicalDayHandler($mailer, $twig, $userRepository, new NullLogger());
        ($handler)($this->createEvent());
    }

    #[Test]
    public function itHandlesMailerFailureGracefully(): void
    {
        $mailer = $this->createMock(MailerInterface::class);
        $twig = $this->createMock(Environment::class);
        $userRepository = $this->createMock(UserRepository::class);

        $twig->method('render')->willReturn('<html>notification</html>');

        $userRepository->method('findAllByTenant')->willReturn([
            $this->createUser('teacher@school.fr', [Role::PROF]),
        ]);

        $mailer->method('send')->willThrowException(new RuntimeException('SMTP error'));

        $handler = new NotifyTeachersPedagogicalDayHandler($mailer, $twig, $userRepository, new NullLogger());
        ($handler)($this->createEvent());

        $this->addToAssertionCount(1);
    }

    private function createEvent(): JourneePedagogiqueAjoutee
    {
        return new JourneePedagogiqueAjoutee(
            entryId: CalendarEntryId::generate(),
            tenantId: TenantId::fromString(self::TENANT_ID),
            academicYearId: AcademicYearId::fromString(self::ACADEMIC_YEAR_ID),
            date: new DateTimeImmutable('2025-03-14'),
            label: 'Formation enseignants',
            occurredOn: new DateTimeImmutable('2026-02-18 10:00:00'),
        );
    }

    /**
     * @param Role[] $roles
     */
    private function createUser(string $email, array $roles): User
    {
        return User::reconstitute(
            id: UserId::generate(),
            email: new Email($email),
            roles: $roles,
            tenantId: TenantId::fromString(self::TENANT_ID),
            schoolName: 'École Test',
            statut: StatutCompte::ACTIF,
            dateNaissance: null,
            createdAt: new DateTimeImmutable('2026-01-01'),
            hashedPassword: 'hashed',
            activatedAt: new DateTimeImmutable('2026-01-02'),
            consentementParental: null,
        );
    }
}
