<?php

declare(strict_types=1);

namespace App\Tests\Unit\Scolarite\Application\Command\DeleteScheduleSlot;

use App\Administration\Domain\Model\SchoolClass\ClassId;
use App\Administration\Domain\Model\Subject\SubjectId;
use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Application\Command\DeleteScheduleSlot\DeleteScheduleSlotCommand;
use App\Scolarite\Application\Command\DeleteScheduleSlot\DeleteScheduleSlotHandler;
use App\Scolarite\Domain\Event\CoursSupprime;
use App\Scolarite\Domain\Exception\ScheduleSlotNotFoundException;
use App\Scolarite\Domain\Model\Schedule\DayOfWeek;
use App\Scolarite\Domain\Model\Schedule\ScheduleSlot;
use App\Scolarite\Domain\Model\Schedule\TimeSlot;
use App\Scolarite\Infrastructure\Persistence\InMemory\InMemoryScheduleSlotRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class DeleteScheduleSlotHandlerTest extends TestCase
{
    private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
    private const string CLASS_ID = '550e8400-e29b-41d4-a716-446655440020';
    private const string SUBJECT_ID = '550e8400-e29b-41d4-a716-446655440030';
    private const string TEACHER_ID = '550e8400-e29b-41d4-a716-446655440010';

    private InMemoryScheduleSlotRepository $repository;
    private DeleteScheduleSlotHandler $handler;

    protected function setUp(): void
    {
        $this->repository = new InMemoryScheduleSlotRepository();
        $clock = new class implements Clock {
            public function now(): DateTimeImmutable
            {
                return new DateTimeImmutable('2026-03-02 15:00:00');
            }
        };

        $this->handler = new DeleteScheduleSlotHandler($this->repository, $clock);
    }

    #[Test]
    public function deletesSlotFromRepository(): void
    {
        $slot = $this->createAndSaveSlot();
        $tenantId = TenantId::fromString(self::TENANT_ID);

        ($this->handler)(new DeleteScheduleSlotCommand(
            tenantId: self::TENANT_ID,
            slotId: (string) $slot->id,
        ));

        self::assertNull($this->repository->findById($slot->id, $tenantId));
    }

    #[Test]
    public function returnsSlotWithCoursSupprime(): void
    {
        $slot = $this->createAndSaveSlot();
        $slot->pullDomainEvents(); // Clear creation event

        $deletedSlot = ($this->handler)(new DeleteScheduleSlotCommand(
            tenantId: self::TENANT_ID,
            slotId: (string) $slot->id,
        ));

        $events = $deletedSlot->pullDomainEvents();
        self::assertCount(1, $events);
        self::assertInstanceOf(CoursSupprime::class, $events[0]);
    }

    #[Test]
    public function throwsWhenSlotNotFound(): void
    {
        $this->expectException(ScheduleSlotNotFoundException::class);

        ($this->handler)(new DeleteScheduleSlotCommand(
            tenantId: self::TENANT_ID,
            slotId: '550e8400-e29b-41d4-a716-446655440099',
        ));
    }

    private function createAndSaveSlot(): ScheduleSlot
    {
        $slot = ScheduleSlot::creer(
            tenantId: TenantId::fromString(self::TENANT_ID),
            classId: ClassId::fromString(self::CLASS_ID),
            subjectId: SubjectId::fromString(self::SUBJECT_ID),
            teacherId: UserId::fromString(self::TEACHER_ID),
            dayOfWeek: DayOfWeek::MONDAY,
            timeSlot: new TimeSlot('08:00', '09:00'),
            room: null,
            isRecurring: true,
            now: new DateTimeImmutable('2026-03-01 10:00:00'),
        );
        $this->repository->save($slot);

        return $slot;
    }
}
