<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Api\Resource;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use App\Scolarite\Application\Query\GetActiveReplacements\ReplacementDto;
use App\Scolarite\Domain\Model\TeacherReplacement\TeacherReplacement;
use App\Scolarite\Infrastructure\Api\Processor\CreateTeacherReplacementProcessor;
use App\Scolarite\Infrastructure\Api\Processor\EndTeacherReplacementProcessor;
use App\Scolarite\Infrastructure\Api\Provider\TeacherReplacementItemProvider;
use App\Scolarite\Infrastructure\Api\Provider\TeacherReplacementsCollectionProvider;
use DateTimeImmutable;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * API Resource pour la gestion des remplacements enseignants.
 *
 * @see Story 2.9 - Désignation Remplaçants Temporaires
 * @see FR9 - Désigner remplaçant temporaire
 */
#[ApiResource(
    shortName: 'TeacherReplacement',
    operations: [
        new GetCollection(
            uriTemplate: '/teacher-replacements',
            provider: TeacherReplacementsCollectionProvider::class,
            name: 'get_teacher_replacements',
        ),
        new Post(
            uriTemplate: '/teacher-replacements',
            processor: CreateTeacherReplacementProcessor::class,
            validationContext: ['groups' => ['Default', 'create']],
            name: 'create_teacher_replacement',
        ),
        new Delete(
            uriTemplate: '/teacher-replacements/{id}',
            provider: TeacherReplacementItemProvider::class,
            processor: EndTeacherReplacementProcessor::class,
            name: 'end_teacher_replacement',
        ),
    ],
)]
final class TeacherReplacementResource
{
    #[ApiProperty(identifier: true)]
    public ?string $id = null;

    #[Assert\NotBlank(message: 'L\'identifiant de l\'enseignant remplacé est requis.', groups: ['create'])]
    public ?string $replacedTeacherId = null;

    #[Assert\NotBlank(message: 'L\'identifiant du remplaçant est requis.', groups: ['create'])]
    public ?string $replacementTeacherId = null;

    #[Assert\NotBlank(message: 'La date de début est requise.', groups: ['create'])]
    public ?string $startDate = null;

    #[Assert\NotBlank(message: 'La date de fin est requise.', groups: ['create'])]
    public ?string $endDate = null;

    /** @var array<array{classId: string, subjectId: string}>|null */
    #[Assert\NotBlank(message: 'Au moins une classe/matière est requise.', groups: ['create'])]
    #[Assert\All(
        constraints: [
            new Assert\Collection(
                fields: [
                    'classId' => [
                        new Assert\NotBlank(message: 'L\'identifiant de la classe est requis.', groups: ['create']),
                        new Assert\Uuid(message: 'L\'identifiant de la classe doit être un UUID valide.', groups: ['create']),
                    ],
                    'subjectId' => [
                        new Assert\NotBlank(message: 'L\'identifiant de la matière est requis.', groups: ['create']),
                        new Assert\Uuid(message: 'L\'identifiant de la matière doit être un UUID valide.', groups: ['create']),
                    ],
                ],
                allowExtraFields: false,
                allowMissingFields: false,
                groups: ['create'],
            ),
        ],
        groups: ['create'],
    )]
    public ?array $classes = null;

    public ?string $reason = null;

    public ?string $status = null;

    public ?DateTimeImmutable $createdAt = null;

    public ?DateTimeImmutable $endedAt = null;

    public static function fromDomain(TeacherReplacement $replacement): self
    {
        $resource = new self();
        $resource->id = (string) $replacement->id;
        $resource->replacedTeacherId = (string) $replacement->replacedTeacherId;
        $resource->replacementTeacherId = (string) $replacement->replacementTeacherId;
        $resource->startDate = $replacement->startDate->format('Y-m-d');
        $resource->endDate = $replacement->endDate->format('Y-m-d');
        $resource->classes = array_map(
            static fn ($pair) => [
                'classId' => (string) $pair->classId,
                'subjectId' => (string) $pair->subjectId,
            ],
            $replacement->classes,
        );
        $resource->reason = $replacement->reason;
        $resource->status = $replacement->status->value;
        $resource->createdAt = $replacement->createdAt;
        $resource->endedAt = $replacement->endedAt;

        return $resource;
    }

    public static function fromDto(ReplacementDto $dto): self
    {
        $resource = new self();
        $resource->id = $dto->id;
        $resource->replacedTeacherId = $dto->replacedTeacherId;
        $resource->replacementTeacherId = $dto->replacementTeacherId;
        $resource->startDate = $dto->startDate->format('Y-m-d');
        $resource->endDate = $dto->endDate->format('Y-m-d');
        $resource->classes = $dto->classes;
        $resource->reason = $dto->reason;
        $resource->status = $dto->status;

        return $resource;
    }
}
