<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Infrastructure\Api\Resource;

use App\Administration\Domain\Model\GradingConfiguration\GradingMode;
use App\Administration\Domain\Model\GradingConfiguration\SchoolGradingConfiguration;
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
use App\Administration\Domain\Model\SchoolClass\SchoolId;
use App\Administration\Infrastructure\Api\Resource\GradingModeResource;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class GradingModeResourceTest extends TestCase
{
    #[Test]
    public function fromDomainMapsAllFields(): void
    {
        $config = SchoolGradingConfiguration::configurer(
            tenantId: TenantId::generate(),
            schoolId: SchoolId::generate(),
            academicYearId: AcademicYearId::generate(),
            mode: GradingMode::NUMERIC_20,
            hasExistingGrades: false,
            configuredAt: new DateTimeImmutable(),
        );

        $resource = GradingModeResource::fromDomain($config);

        self::assertSame('numeric_20', $resource->mode);
        self::assertSame('Notes /20', $resource->label);
        self::assertSame(20, $resource->scaleMax);
        self::assertTrue($resource->isNumeric);
        self::assertTrue($resource->calculatesAverage);
        self::assertSame((string) $config->academicYearId, $resource->academicYearId);
    }

    #[Test]
    public function fromDomainMapsCompetenciesMode(): void
    {
        $config = SchoolGradingConfiguration::configurer(
            tenantId: TenantId::generate(),
            schoolId: SchoolId::generate(),
            academicYearId: AcademicYearId::generate(),
            mode: GradingMode::COMPETENCIES,
            hasExistingGrades: false,
            configuredAt: new DateTimeImmutable(),
        );

        $resource = GradingModeResource::fromDomain($config);

        self::assertSame('competencies', $resource->mode);
        self::assertSame('Compétences', $resource->label);
        self::assertNull($resource->scaleMax);
        self::assertFalse($resource->isNumeric);
        self::assertFalse($resource->calculatesAverage);
    }

    #[Test]
    public function fromDomainMapsNoGradesMode(): void
    {
        $config = SchoolGradingConfiguration::configurer(
            tenantId: TenantId::generate(),
            schoolId: SchoolId::generate(),
            academicYearId: AcademicYearId::generate(),
            mode: GradingMode::NO_GRADES,
            hasExistingGrades: false,
            configuredAt: new DateTimeImmutable(),
        );

        $resource = GradingModeResource::fromDomain($config);

        self::assertSame('no_grades', $resource->mode);
        self::assertSame('Sans notes', $resource->label);
        self::assertNull($resource->scaleMax);
        self::assertFalse($resource->isNumeric);
        self::assertFalse($resource->calculatesAverage);
    }

    #[Test]
    public function defaultForYearUsesNumeric20(): void
    {
        $yearId = 'some-year-id';
        $resource = GradingModeResource::defaultForYear($yearId);

        self::assertSame($yearId, $resource->academicYearId);
        self::assertSame('numeric_20', $resource->mode);
        self::assertSame('Notes /20', $resource->label);
        self::assertSame(20, $resource->scaleMax);
        self::assertTrue($resource->isNumeric);
        self::assertTrue($resource->calculatesAverage);
        self::assertFalse($resource->hasExistingGrades);
    }

    #[Test]
    public function allAvailableModesReturnsAllFiveModes(): void
    {
        $modes = GradingModeResource::allAvailableModes();

        self::assertCount(5, $modes);

        $values = array_column($modes, 'value');
        self::assertContains('numeric_20', $values);
        self::assertContains('numeric_10', $values);
        self::assertContains('letters', $values);
        self::assertContains('competencies', $values);
        self::assertContains('no_grades', $values);
    }

    #[Test]
    public function allAvailableModesContainsLabels(): void
    {
        $modes = GradingModeResource::allAvailableModes();

        foreach ($modes as $mode) {
            self::assertArrayHasKey('value', $mode);
            self::assertArrayHasKey('label', $mode);
            self::assertNotEmpty($mode['label']);
        }
    }
}
