<?php

declare(strict_types=1);

namespace App\Tests\Unit\Scolarite\Domain\Service;

use App\Administration\Domain\Model\SchoolCalendar\CalendarEntry;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryId;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryType;
use App\Administration\Domain\Model\SchoolCalendar\SchoolCalendar;
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
use App\Scolarite\Domain\Exception\DateEcheanceInvalideException;
use App\Scolarite\Domain\Service\DueDateValidator;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class DueDateValidatorTest extends TestCase
{
    private DueDateValidator $validator;

    protected function setUp(): void
    {
        $this->validator = new DueDateValidator();
    }

    #[Test]
    public function acceptsValidFutureSchoolDay(): void
    {
        $now = new DateTimeImmutable('2026-03-12 10:00:00'); // Jeudi
        $dueDate = new DateTimeImmutable('2026-03-16'); // Lundi
        $calendar = $this->createEmptyCalendar();

        $this->validator->valider($dueDate, $now, $calendar);

        $this->addToAssertionCount(1);
    }

    #[Test]
    public function rejectsPastDate(): void
    {
        $now = new DateTimeImmutable('2026-03-12 10:00:00');
        $dueDate = new DateTimeImmutable('2026-03-11');
        $calendar = $this->createEmptyCalendar();

        $this->expectException(DateEcheanceInvalideException::class);
        $this->expectExceptionMessageMatches('/futur/');

        $this->validator->valider($dueDate, $now, $calendar);
    }

    #[Test]
    public function rejectsTodayDate(): void
    {
        $now = new DateTimeImmutable('2026-03-12 10:00:00');
        $dueDate = new DateTimeImmutable('2026-03-12');
        $calendar = $this->createEmptyCalendar();

        $this->expectException(DateEcheanceInvalideException::class);
        $this->expectExceptionMessageMatches('/futur/');

        $this->validator->valider($dueDate, $now, $calendar);
    }

    #[Test]
    public function acceptsTomorrowDate(): void
    {
        $now = new DateTimeImmutable('2026-03-12 10:00:00'); // Jeudi
        $dueDate = new DateTimeImmutable('2026-03-13'); // Vendredi
        $calendar = $this->createEmptyCalendar();

        $this->validator->valider($dueDate, $now, $calendar);

        $this->addToAssertionCount(1);
    }

    #[Test]
    public function rejectsWeekendDate(): void
    {
        $now = new DateTimeImmutable('2026-03-12 10:00:00');
        $dueDate = new DateTimeImmutable('2026-03-14'); // Samedi
        $calendar = $this->createEmptyCalendar();

        $this->expectException(DateEcheanceInvalideException::class);
        $this->expectExceptionMessageMatches('/weekend/');

        $this->validator->valider($dueDate, $now, $calendar);
    }

    #[Test]
    public function rejectsHolidayDate(): void
    {
        $now = new DateTimeImmutable('2026-03-12 10:00:00');
        $dueDate = new DateTimeImmutable('2026-04-06'); // Lundi
        $calendar = $this->createCalendarWithVacation(
            new DateTimeImmutable('2026-04-04'),
            new DateTimeImmutable('2026-04-19'),
            'Vacances de printemps',
        );

        $this->expectException(DateEcheanceInvalideException::class);
        $this->expectExceptionMessageMatches('/Vacances de printemps/');

        $this->validator->valider($dueDate, $now, $calendar);
    }

    private function createEmptyCalendar(): SchoolCalendar
    {
        return SchoolCalendar::reconstitute(
            tenantId: TenantId::fromString('550e8400-e29b-41d4-a716-446655440001'),
            academicYearId: AcademicYearId::fromString('550e8400-e29b-41d4-a716-446655440002'),
            zone: null,
            entries: [],
        );
    }

    private function createCalendarWithVacation(
        DateTimeImmutable $start,
        DateTimeImmutable $end,
        string $label,
    ): SchoolCalendar {
        return SchoolCalendar::reconstitute(
            tenantId: TenantId::fromString('550e8400-e29b-41d4-a716-446655440001'),
            academicYearId: AcademicYearId::fromString('550e8400-e29b-41d4-a716-446655440002'),
            zone: null,
            entries: [
                new CalendarEntry(
                    id: CalendarEntryId::generate(),
                    type: CalendarEntryType::VACATION,
                    startDate: $start,
                    endDate: $end,
                    label: $label,
                ),
            ],
        );
    }
}
