<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Infrastructure\Service;

use App\Administration\Infrastructure\Service\CurrentAcademicYearResolver;
use App\Shared\Domain\Clock;
use App\Shared\Infrastructure\Tenant\TenantConfig;
use App\Shared\Infrastructure\Tenant\TenantContext;
use App\Shared\Infrastructure\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class CurrentAcademicYearResolverTest extends TestCase
{
    private const string TENANT_UUID = '550e8400-e29b-41d4-a716-446655440001';

    #[Test]
    public function itPassesThroughValidUuid(): void
    {
        $resolver = $this->createResolver('2026-02-05 10:00:00');
        $uuid = '550e8400-e29b-41d4-a716-446655440099';

        self::assertSame($uuid, $resolver->resolve($uuid));
    }

    #[Test]
    public function itReturnsNullForInvalidIdentifier(): void
    {
        $resolver = $this->createResolver('2026-02-05 10:00:00');

        self::assertNull($resolver->resolve('invalid'));
        self::assertNull($resolver->resolve(''));
        self::assertNull($resolver->resolve('past'));
    }

    #[Test]
    public function itResolvesCurrentBeforeSeptember(): void
    {
        // February 2026 → school year 2025-2026
        $resolver = $this->createResolver('2026-02-05 10:00:00');
        $result = $resolver->resolve('current');

        self::assertNotNull($result);
        self::assertTrue(\Ramsey\Uuid\Uuid::isValid($result));
    }

    #[Test]
    public function itResolvesCurrentAfterSeptember(): void
    {
        // October 2025 → school year 2025-2026
        $resolver = $this->createResolver('2025-10-15 10:00:00');
        $result = $resolver->resolve('current');

        self::assertNotNull($result);
        self::assertTrue(\Ramsey\Uuid\Uuid::isValid($result));
    }

    #[Test]
    public function itResolvesSameUuidForSameSchoolYear(): void
    {
        // Both dates are in school year 2025-2026
        $resolverOct = $this->createResolver('2025-10-15 10:00:00');
        $resolverFeb = $this->createResolver('2026-02-05 10:00:00');

        self::assertSame(
            $resolverOct->resolve('current'),
            $resolverFeb->resolve('current'),
        );
    }

    #[Test]
    public function itResolvesDifferentUuidForDifferentSchoolYears(): void
    {
        // October 2025 → 2025-2026, October 2026 → 2026-2027
        $resolver2025 = $this->createResolver('2025-10-15 10:00:00');
        $resolver2026 = $this->createResolver('2026-10-15 10:00:00');

        self::assertNotSame(
            $resolver2025->resolve('current'),
            $resolver2026->resolve('current'),
        );
    }

    #[Test]
    public function itResolvesNextYear(): void
    {
        // February 2026, current = 2025-2026, next = 2026-2027
        $resolver = $this->createResolver('2026-02-05 10:00:00');

        $current = $resolver->resolve('current');
        $next = $resolver->resolve('next');

        self::assertNotNull($next);
        self::assertTrue(\Ramsey\Uuid\Uuid::isValid($next));
        self::assertNotSame($current, $next);
    }

    #[Test]
    public function itResolvesPreviousYear(): void
    {
        // February 2026, current = 2025-2026, previous = 2024-2025
        $resolver = $this->createResolver('2026-02-05 10:00:00');

        $current = $resolver->resolve('current');
        $previous = $resolver->resolve('previous');

        self::assertNotNull($previous);
        self::assertTrue(\Ramsey\Uuid\Uuid::isValid($previous));
        self::assertNotSame($current, $previous);
    }

    #[Test]
    public function nextOfCurrentYearMatchesCurrentOfNextYear(): void
    {
        // "next" from Feb 2026 should equal "current" from Oct 2026
        $resolverFeb2026 = $this->createResolver('2026-02-05 10:00:00');
        $resolverOct2026 = $this->createResolver('2026-10-15 10:00:00');

        self::assertSame(
            $resolverFeb2026->resolve('next'),
            $resolverOct2026->resolve('current'),
        );
    }

    #[Test]
    public function previousOfCurrentYearMatchesCurrentOfPreviousYear(): void
    {
        // "previous" from Feb 2026 (2024-2025) should equal "current" from Oct 2024
        $resolverFeb2026 = $this->createResolver('2026-02-05 10:00:00');
        $resolverOct2024 = $this->createResolver('2024-10-15 10:00:00');

        self::assertSame(
            $resolverFeb2026->resolve('previous'),
            $resolverOct2024->resolve('current'),
        );
    }

    #[Test]
    public function itResolvesDifferentUuidsForDifferentTenants(): void
    {
        $otherTenantUuid = '550e8400-e29b-41d4-a716-446655440099';

        $resolver1 = $this->createResolver('2026-02-05 10:00:00', self::TENANT_UUID);
        $resolver2 = $this->createResolver('2026-02-05 10:00:00', $otherTenantUuid);

        self::assertNotSame(
            $resolver1->resolve('current'),
            $resolver2->resolve('current'),
        );
    }

    #[Test]
    public function itIsDeterministic(): void
    {
        $resolver = $this->createResolver('2026-02-05 10:00:00');

        self::assertSame(
            $resolver->resolve('current'),
            $resolver->resolve('current'),
        );
    }

    #[Test]
    public function septemberBelongsToNewSchoolYear(): void
    {
        // September 1st 2026 should be in school year 2026-2027
        $resolverSept = $this->createResolver('2026-09-01 08:00:00');
        $resolverOct = $this->createResolver('2026-10-15 10:00:00');

        self::assertSame(
            $resolverSept->resolve('current'),
            $resolverOct->resolve('current'),
        );
    }

    #[Test]
    public function augustBelongsToPreviousSchoolYear(): void
    {
        // August 31st 2026 should still be in school year 2025-2026
        $resolverAug = $this->createResolver('2026-08-31 23:59:59');
        $resolverFeb = $this->createResolver('2026-02-05 10:00:00');

        self::assertSame(
            $resolverAug->resolve('current'),
            $resolverFeb->resolve('current'),
        );
    }

    private function createResolver(string $dateTime, string $tenantUuid = self::TENANT_UUID): CurrentAcademicYearResolver
    {
        $tenantContext = new TenantContext();
        $tenantContext->setCurrentTenant(new TenantConfig(
            tenantId: TenantId::fromString($tenantUuid),
            subdomain: 'test',
            databaseUrl: 'sqlite:///:memory:',
        ));

        $clock = new class($dateTime) implements Clock {
            public function __construct(private readonly string $dateTime)
            {
            }

            public function now(): DateTimeImmutable
            {
                return new DateTimeImmutable($this->dateTime);
            }
        };

        return new CurrentAcademicYearResolver($tenantContext, $clock);
    }
}
