<?php

declare(strict_types=1);

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

use App\Administration\Domain\Exception\InvalidPeriodDatesException;
use App\Administration\Domain\Model\AcademicYear\AcademicPeriod;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class AcademicPeriodTest extends TestCase
{
    #[Test]
    public function itCreatesValidPeriod(): void
    {
        $period = new AcademicPeriod(
            sequence: 1,
            label: 'T1',
            startDate: new DateTimeImmutable('2025-09-01'),
            endDate: new DateTimeImmutable('2025-11-30'),
        );

        self::assertSame(1, $period->sequence);
        self::assertSame('T1', $period->label);
        self::assertSame('2025-09-01', $period->startDate->format('Y-m-d'));
        self::assertSame('2025-11-30', $period->endDate->format('Y-m-d'));
    }

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

        new AcademicPeriod(
            sequence: 1,
            label: 'T1',
            startDate: new DateTimeImmutable('2025-11-30'),
            endDate: new DateTimeImmutable('2025-09-01'),
        );
    }

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

        new AcademicPeriod(
            sequence: 1,
            label: 'T1',
            startDate: new DateTimeImmutable('2025-09-01'),
            endDate: new DateTimeImmutable('2025-09-01'),
        );
    }

    #[Test]
    public function itDetectsDateWithinPeriod(): void
    {
        $period = new AcademicPeriod(
            sequence: 1,
            label: 'T1',
            startDate: new DateTimeImmutable('2025-09-01'),
            endDate: new DateTimeImmutable('2025-11-30'),
        );

        self::assertTrue($period->containsDate(new DateTimeImmutable('2025-10-15')));
        self::assertTrue($period->containsDate(new DateTimeImmutable('2025-09-01')));
        self::assertTrue($period->containsDate(new DateTimeImmutable('2025-11-30')));
        self::assertFalse($period->containsDate(new DateTimeImmutable('2025-08-31')));
        self::assertFalse($period->containsDate(new DateTimeImmutable('2025-12-01')));
    }

    #[Test]
    public function itIncludesLastDayRegardlessOfTime(): void
    {
        $period = new AcademicPeriod(
            sequence: 1,
            label: 'T1',
            startDate: new DateTimeImmutable('2025-09-01'),
            endDate: new DateTimeImmutable('2025-11-30'),
        );

        // Last day at 15:00 must still be "within" the period
        self::assertTrue($period->containsDate(new DateTimeImmutable('2025-11-30 15:00:00')));
        self::assertFalse($period->isPast(new DateTimeImmutable('2025-11-30 23:59:59')));
        self::assertTrue($period->isPast(new DateTimeImmutable('2025-12-01 00:00:01')));

        // daysRemaining on last day should be 0 (same day)
        self::assertSame(0, $period->daysRemaining(new DateTimeImmutable('2025-11-30 15:00:00')));
    }

    #[Test]
    public function itCalculatesDaysRemaining(): void
    {
        $period = new AcademicPeriod(
            sequence: 1,
            label: 'T1',
            startDate: new DateTimeImmutable('2025-09-01'),
            endDate: new DateTimeImmutable('2025-11-30'),
        );

        // During the period
        self::assertSame(30, $period->daysRemaining(new DateTimeImmutable('2025-10-31')));

        // After the period
        self::assertSame(0, $period->daysRemaining(new DateTimeImmutable('2025-12-01')));

        // Before the period: returns total period length
        self::assertSame(90, $period->daysRemaining(new DateTimeImmutable('2025-08-01')));
    }

    #[Test]
    public function itDetectsPastPeriod(): void
    {
        $period = new AcademicPeriod(
            sequence: 1,
            label: 'T1',
            startDate: new DateTimeImmutable('2025-09-01'),
            endDate: new DateTimeImmutable('2025-11-30'),
        );

        self::assertTrue($period->isPast(new DateTimeImmutable('2025-12-01')));
        self::assertFalse($period->isPast(new DateTimeImmutable('2025-11-30')));
        self::assertFalse($period->isPast(new DateTimeImmutable('2025-10-15')));
    }
}
