<?php

declare(strict_types=1);

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

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\EndReplacement\EndReplacementCommand;
use App\Scolarite\Application\Command\EndReplacement\EndReplacementHandler;
use App\Scolarite\Domain\Exception\RemplacementDejaTermineException;
use App\Scolarite\Domain\Exception\RemplacementNotFoundException;
use App\Scolarite\Domain\Model\TeacherReplacement\ClassSubjectPair;
use App\Scolarite\Domain\Model\TeacherReplacement\ReplacementStatus;
use App\Scolarite\Domain\Model\TeacherReplacement\TeacherReplacement;
use App\Scolarite\Infrastructure\Persistence\InMemory\InMemoryTeacherReplacementRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class EndReplacementHandlerTest extends TestCase
{
    private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
    private const string REPLACED_TEACHER_ID = '550e8400-e29b-41d4-a716-446655440010';
    private const string REPLACEMENT_TEACHER_ID = '550e8400-e29b-41d4-a716-446655440011';
    private const string CREATED_BY_ID = '550e8400-e29b-41d4-a716-446655440099';

    private InMemoryTeacherReplacementRepository $replacementRepository;
    private Clock $clock;

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

    #[Test]
    public function itEndsReplacementSuccessfully(): void
    {
        $replacement = $this->createAndSaveReplacement();
        $handler = $this->createHandler();

        $handler(new EndReplacementCommand(
            replacementId: (string) $replacement->id,
            tenantId: self::TENANT_ID,
        ));

        $ended = $this->replacementRepository->get($replacement->id, TenantId::fromString(self::TENANT_ID));
        self::assertSame(ReplacementStatus::ENDED, $ended->status);
        self::assertNotNull($ended->endedAt);
    }

    #[Test]
    public function itThrowsWhenReplacementNotFound(): void
    {
        $handler = $this->createHandler();

        $this->expectException(RemplacementNotFoundException::class);
        $handler(new EndReplacementCommand(
            replacementId: '550e8400-e29b-41d4-a716-446655440088',
            tenantId: self::TENANT_ID,
        ));
    }

    #[Test]
    public function itThrowsWhenReplacementAlreadyEnded(): void
    {
        $replacement = $this->createAndSaveReplacement();
        $replacement->terminer(new DateTimeImmutable('2026-03-10'));
        $this->replacementRepository->save($replacement);

        $handler = $this->createHandler();

        $this->expectException(RemplacementDejaTermineException::class);
        $handler(new EndReplacementCommand(
            replacementId: (string) $replacement->id,
            tenantId: self::TENANT_ID,
        ));
    }

    private function createAndSaveReplacement(): TeacherReplacement
    {
        $replacement = TeacherReplacement::designer(
            tenantId: TenantId::fromString(self::TENANT_ID),
            replacedTeacherId: UserId::fromString(self::REPLACED_TEACHER_ID),
            replacementTeacherId: UserId::fromString(self::REPLACEMENT_TEACHER_ID),
            startDate: new DateTimeImmutable('2026-03-01'),
            endDate: new DateTimeImmutable('2026-03-31'),
            classes: [
                new ClassSubjectPair(
                    ClassId::fromString('550e8400-e29b-41d4-a716-446655440020'),
                    SubjectId::fromString('550e8400-e29b-41d4-a716-446655440030'),
                ),
            ],
            reason: null,
            createdBy: UserId::fromString(self::CREATED_BY_ID),
            now: new DateTimeImmutable('2026-02-15 10:00:00'),
        );

        $this->replacementRepository->save($replacement);

        return $replacement;
    }

    private function createHandler(): EndReplacementHandler
    {
        return new EndReplacementHandler(
            $this->replacementRepository,
            $this->clock,
        );
    }
}
