<?php

declare(strict_types=1);

namespace App\Tests\Unit\Scolarite\Application\Query\GetActiveReplacements;

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\Query\GetActiveReplacements\ReplacementDto;
use App\Scolarite\Domain\Model\TeacherReplacement\ClassSubjectPair;
use App\Scolarite\Domain\Model\TeacherReplacement\ReplacementStatus;
use App\Scolarite\Domain\Model\TeacherReplacement\TeacherReplacement;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class ReplacementDtoTest 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 CLASS_ID = '550e8400-e29b-41d4-a716-446655440020';
    private const string SUBJECT_ID = '550e8400-e29b-41d4-a716-446655440030';
    private const string CREATED_BY_ID = '550e8400-e29b-41d4-a716-446655440099';

    #[Test]
    public function fromDomainCreatesCorrectDto(): void
    {
        $replacement = $this->createReplacement();

        $dto = ReplacementDto::fromDomain($replacement);

        self::assertSame((string) $replacement->id, $dto->id);
        self::assertSame(self::REPLACED_TEACHER_ID, $dto->replacedTeacherId);
        self::assertSame(self::REPLACEMENT_TEACHER_ID, $dto->replacementTeacherId);
        self::assertEquals(new DateTimeImmutable('2026-03-01'), $dto->startDate);
        self::assertEquals(new DateTimeImmutable('2026-03-31'), $dto->endDate);
        self::assertSame(ReplacementStatus::ACTIVE->value, $dto->status);
        self::assertSame('Congé maladie', $dto->reason);
    }

    #[Test]
    public function fromDomainPreservesAllClassSubjectPairs(): void
    {
        $replacement = $this->createReplacementWithMultipleClasses();

        $dto = ReplacementDto::fromDomain($replacement);

        self::assertCount(2, $dto->classes);
        self::assertSame(self::CLASS_ID, $dto->classes[0]['classId']);
        self::assertSame(self::SUBJECT_ID, $dto->classes[0]['subjectId']);
        self::assertSame('550e8400-e29b-41d4-a716-446655440021', $dto->classes[1]['classId']);
        self::assertSame('550e8400-e29b-41d4-a716-446655440031', $dto->classes[1]['subjectId']);
    }

    #[Test]
    public function fromDomainPreservesNullReason(): void
    {
        $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(self::CLASS_ID),
                    SubjectId::fromString(self::SUBJECT_ID),
                ),
            ],
            reason: null,
            createdBy: UserId::fromString(self::CREATED_BY_ID),
            now: new DateTimeImmutable('2026-02-15 10:00:00'),
        );

        $dto = ReplacementDto::fromDomain($replacement);

        self::assertNull($dto->reason);
    }

    private function createReplacement(): TeacherReplacement
    {
        return 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(self::CLASS_ID),
                    SubjectId::fromString(self::SUBJECT_ID),
                ),
            ],
            reason: 'Congé maladie',
            createdBy: UserId::fromString(self::CREATED_BY_ID),
            now: new DateTimeImmutable('2026-02-15 10:00:00'),
        );
    }

    private function createReplacementWithMultipleClasses(): TeacherReplacement
    {
        return 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(self::CLASS_ID),
                    SubjectId::fromString(self::SUBJECT_ID),
                ),
                new ClassSubjectPair(
                    ClassId::fromString('550e8400-e29b-41d4-a716-446655440021'),
                    SubjectId::fromString('550e8400-e29b-41d4-a716-446655440031'),
                ),
            ],
            reason: 'Congé maladie',
            createdBy: UserId::fromString(self::CREATED_BY_ID),
            now: new DateTimeImmutable('2026-02-15 10:00:00'),
        );
    }
}
