<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Api\Resource;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put;
use App\Administration\Domain\Model\GradingConfiguration\GradingMode;
use App\Administration\Domain\Model\GradingConfiguration\SchoolGradingConfiguration;
use App\Administration\Infrastructure\Api\Processor\ConfigureGradingModeProcessor;
use App\Administration\Infrastructure\Api\Provider\GradingModeProvider;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * API Resource pour la configuration du mode de notation.
 *
 * @see FR24 - Supporter différentes pédagogies
 */
#[ApiResource(
    shortName: 'GradingMode',
    operations: [
        new Get(
            uriTemplate: '/academic-years/{academicYearId}/grading-mode',
            provider: GradingModeProvider::class,
            name: 'get_grading_mode',
        ),
        new Put(
            uriTemplate: '/academic-years/{academicYearId}/grading-mode',
            read: false,
            processor: ConfigureGradingModeProcessor::class,
            name: 'configure_grading_mode',
        ),
    ],
)]
final class GradingModeResource
{
    #[ApiProperty(identifier: true)]
    public ?string $academicYearId = null;

    #[Assert\NotBlank(message: 'Le mode de notation est requis.')]
    #[Assert\Choice(
        choices: ['numeric_20', 'numeric_10', 'letters', 'competencies', 'no_grades'],
        message: 'Mode de notation invalide. Valeurs acceptées : numeric_20, numeric_10, letters, competencies, no_grades.',
    )]
    public ?string $mode = null;

    #[ApiProperty(readable: true, writable: false)]
    public ?string $label = null;

    #[ApiProperty(readable: true, writable: false)]
    public ?int $scaleMax = null;

    #[ApiProperty(readable: true, writable: false)]
    public ?bool $isNumeric = null;

    #[ApiProperty(readable: true, writable: false)]
    public ?bool $calculatesAverage = null;

    #[ApiProperty(readable: true, writable: false)]
    public ?bool $hasExistingGrades = null;

    /** @var array<array{value: string, label: string}>|null */
    #[ApiProperty(readable: true, writable: false)]
    public ?array $availableModes = null;

    public static function fromDomain(SchoolGradingConfiguration $config): self
    {
        $resource = new self();
        $resource->academicYearId = (string) $config->academicYearId;
        $resource->mode = $config->gradingConfiguration->mode->value;
        $resource->label = $config->gradingConfiguration->mode->label();
        $resource->scaleMax = $config->gradingConfiguration->scaleMax();
        $resource->isNumeric = $config->gradingConfiguration->estNumerique();
        $resource->calculatesAverage = $config->gradingConfiguration->calculeMoyenne();

        return $resource;
    }

    public static function defaultForYear(string $academicYearId): self
    {
        $resource = new self();
        $resource->academicYearId = $academicYearId;
        $resource->mode = SchoolGradingConfiguration::DEFAULT_MODE->value;
        $resource->label = SchoolGradingConfiguration::DEFAULT_MODE->label();
        $resource->scaleMax = SchoolGradingConfiguration::DEFAULT_MODE->scaleMax();
        $resource->isNumeric = SchoolGradingConfiguration::DEFAULT_MODE->estNumerique();
        $resource->calculatesAverage = SchoolGradingConfiguration::DEFAULT_MODE->calculeMoyenne();
        $resource->hasExistingGrades = false;

        return $resource;
    }

    /**
     * @return array<array{value: string, label: string}>
     */
    public static function allAvailableModes(): array
    {
        return array_map(
            static fn (GradingMode $mode) => [
                'value' => $mode->value,
                'label' => $mode->label(),
            ],
            GradingMode::cases(),
        );
    }
}
