<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Domain\Model\SchoolCalendar;

use App\Administration\Domain\Exception\CalendrierDatesInvalidesException;
use App\Administration\Domain\Exception\CalendrierLabelInvalideException;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntry;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryId;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryType;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class CalendarEntryTest extends TestCase
{
    #[Test]
    public function creationValide(): void
    {
        $entry = $this->createHoliday();

        self::assertSame(CalendarEntryType::HOLIDAY, $entry->type);
        self::assertSame('Toussaint', $entry->label);
        self::assertSame('2024-11-01', $entry->startDate->format('Y-m-d'));
        self::assertSame('2024-11-01', $entry->endDate->format('Y-m-d'));
        self::assertNull($entry->description);
    }

    #[Test]
    public function creationAvecDescription(): void
    {
        $entry = new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::PEDAGOGICAL_DAY,
            startDate: new DateTimeImmutable('2025-03-14'),
            endDate: new DateTimeImmutable('2025-03-14'),
            label: 'Formation enseignants',
            description: 'Journée de formation continue',
        );

        self::assertSame('Journée de formation continue', $entry->description);
    }

    #[Test]
    public function creationPeriodeVacances(): void
    {
        $entry = new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::VACATION,
            startDate: new DateTimeImmutable('2024-10-19'),
            endDate: new DateTimeImmutable('2024-11-03'),
            label: 'Vacances de la Toussaint',
        );

        self::assertSame(CalendarEntryType::VACATION, $entry->type);
        self::assertSame('2024-10-19', $entry->startDate->format('Y-m-d'));
        self::assertSame('2024-11-03', $entry->endDate->format('Y-m-d'));
    }

    #[Test]
    public function labelEstTrimme(): void
    {
        $entry = new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::HOLIDAY,
            startDate: new DateTimeImmutable('2024-11-01'),
            endDate: new DateTimeImmutable('2024-11-01'),
            label: '  Toussaint  ',
        );

        self::assertSame('Toussaint', $entry->label);
    }

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

        new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::HOLIDAY,
            startDate: new DateTimeImmutable('2024-11-02'),
            endDate: new DateTimeImmutable('2024-11-01'),
            label: 'Invalid',
        );
    }

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

        new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::HOLIDAY,
            startDate: new DateTimeImmutable('2024-11-01'),
            endDate: new DateTimeImmutable('2024-11-01'),
            label: '',
        );
    }

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

        new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::HOLIDAY,
            startDate: new DateTimeImmutable('2024-11-01'),
            endDate: new DateTimeImmutable('2024-11-01'),
            label: 'A',
        );
    }

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

        new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::HOLIDAY,
            startDate: new DateTimeImmutable('2024-11-01'),
            endDate: new DateTimeImmutable('2024-11-01'),
            label: str_repeat('A', 101),
        );
    }

    #[Test]
    public function couvreRetourneTruePourDateDansLaPeriode(): void
    {
        $entry = new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::VACATION,
            startDate: new DateTimeImmutable('2024-10-19'),
            endDate: new DateTimeImmutable('2024-11-03'),
            label: 'Vacances Toussaint',
        );

        self::assertTrue($entry->couvre(new DateTimeImmutable('2024-10-19')));
        self::assertTrue($entry->couvre(new DateTimeImmutable('2024-10-25')));
        self::assertTrue($entry->couvre(new DateTimeImmutable('2024-11-03')));
    }

    #[Test]
    public function couvreRetourneFalsePourDateHorsPeriode(): void
    {
        $entry = new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::VACATION,
            startDate: new DateTimeImmutable('2024-10-19'),
            endDate: new DateTimeImmutable('2024-11-03'),
            label: 'Vacances Toussaint',
        );

        self::assertFalse($entry->couvre(new DateTimeImmutable('2024-10-18')));
        self::assertFalse($entry->couvre(new DateTimeImmutable('2024-11-04')));
    }

    #[Test]
    public function couvreJourUnique(): void
    {
        $entry = $this->createHoliday();

        self::assertTrue($entry->couvre(new DateTimeImmutable('2024-11-01')));
        self::assertFalse($entry->couvre(new DateTimeImmutable('2024-10-31')));
        self::assertFalse($entry->couvre(new DateTimeImmutable('2024-11-02')));
    }

    private function createHoliday(): CalendarEntry
    {
        return new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::HOLIDAY,
            startDate: new DateTimeImmutable('2024-11-01'),
            endDate: new DateTimeImmutable('2024-11-01'),
            label: 'Toussaint',
        );
    }
}
