<?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\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use App\Scolarite\Application\Query\GetScheduleSlots\ScheduleSlotDto;
use App\Scolarite\Domain\Model\Schedule\ScheduleSlot;
use App\Scolarite\Infrastructure\Api\Processor\CreateScheduleSlotProcessor;
use App\Scolarite\Infrastructure\Api\Processor\DeleteScheduleSlotProcessor;
use App\Scolarite\Infrastructure\Api\Processor\UpdateScheduleSlotProcessor;
use App\Scolarite\Infrastructure\Api\Provider\ScheduleSlotCollectionProvider;
use App\Scolarite\Infrastructure\Api\Provider\ScheduleSlotItemProvider;
use DateTimeImmutable;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * API Resource pour la gestion de l'emploi du temps.
 *
 * @see Story 4.1 - Création et Modification de l'Emploi du Temps
 * @see FR26 - Créer et modifier l'emploi du temps des classes
 */
#[ApiResource(
    shortName: 'ScheduleSlot',
    operations: [
        new GetCollection(
            uriTemplate: '/schedule/slots',
            provider: ScheduleSlotCollectionProvider::class,
            name: 'get_schedule_slots',
        ),
        new Get(
            uriTemplate: '/schedule/slots/{id}',
            provider: ScheduleSlotItemProvider::class,
            name: 'get_schedule_slot',
        ),
        new Post(
            uriTemplate: '/schedule/slots',
            processor: CreateScheduleSlotProcessor::class,
            validationContext: ['groups' => ['Default', 'create']],
            name: 'create_schedule_slot',
        ),
        new Patch(
            uriTemplate: '/schedule/slots/{id}',
            provider: ScheduleSlotItemProvider::class,
            processor: UpdateScheduleSlotProcessor::class,
            validationContext: ['groups' => ['Default', 'update']],
            name: 'update_schedule_slot',
        ),
        new Delete(
            uriTemplate: '/schedule/slots/{id}',
            provider: ScheduleSlotItemProvider::class,
            processor: DeleteScheduleSlotProcessor::class,
            name: 'delete_schedule_slot',
        ),
    ],
)]
final class ScheduleSlotResource
{
    #[ApiProperty(identifier: true)]
    public ?string $id = null;

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

    #[Assert\NotBlank(message: 'La matière est requise.', groups: ['create'])]
    public ?string $subjectId = null;

    #[Assert\NotBlank(message: "L'enseignant est requis.", groups: ['create'])]
    public ?string $teacherId = null;

    #[Assert\NotNull(message: 'Le jour de la semaine est requis.', groups: ['create'])]
    #[Assert\Range(min: 1, max: 7, notInRangeMessage: 'Le jour doit être compris entre 1 (lundi) et 7 (dimanche).')]
    public ?int $dayOfWeek = null;

    #[Assert\NotBlank(message: "L'heure de début est requise.", groups: ['create'])]
    #[Assert\Regex(pattern: '/^([01]\d|2[0-3]):[0-5]\d$/', message: "L'heure doit être au format HH:MM.")]
    public ?string $startTime = null;

    #[Assert\NotBlank(message: "L'heure de fin est requise.", groups: ['create'])]
    #[Assert\Regex(pattern: '/^([01]\d|2[0-3]):[0-5]\d$/', message: "L'heure doit être au format HH:MM.")]
    public ?string $endTime = null;

    #[Assert\Length(max: 50, maxMessage: 'Le nom de la salle ne peut pas dépasser {{ limit }} caractères.')]
    public ?string $room = null;

    public ?bool $isRecurring = null;

    /**
     * Si true, forcer la création/modification malgré les conflits.
     */
    #[ApiProperty(readable: false)]
    public ?bool $forceConflicts = null;

    /**
     * Conflits détectés lors de la création/modification.
     * Renvoyé en réponse si des conflits existent.
     *
     * @var array<array{type: string, description: string, slotId: string}>|null
     */
    #[ApiProperty(readable: true, writable: false)]
    public ?array $conflicts = null;

    public ?DateTimeImmutable $createdAt = null;

    public ?DateTimeImmutable $updatedAt = null;

    public static function fromDomain(ScheduleSlot $slot): self
    {
        $resource = new self();
        $resource->id = (string) $slot->id;
        $resource->classId = (string) $slot->classId;
        $resource->subjectId = (string) $slot->subjectId;
        $resource->teacherId = (string) $slot->teacherId;
        $resource->dayOfWeek = $slot->dayOfWeek->value;
        $resource->startTime = $slot->timeSlot->startTime;
        $resource->endTime = $slot->timeSlot->endTime;
        $resource->room = $slot->room;
        $resource->isRecurring = $slot->isRecurring;
        $resource->createdAt = $slot->createdAt;
        $resource->updatedAt = $slot->updatedAt;

        return $resource;
    }

    public static function fromDto(ScheduleSlotDto $dto): self
    {
        $resource = new self();
        $resource->id = $dto->id;
        $resource->classId = $dto->classId;
        $resource->subjectId = $dto->subjectId;
        $resource->teacherId = $dto->teacherId;
        $resource->dayOfWeek = $dto->dayOfWeek;
        $resource->startTime = $dto->startTime;
        $resource->endTime = $dto->endTime;
        $resource->room = $dto->room;
        $resource->isRecurring = $dto->isRecurring;
        $resource->createdAt = $dto->createdAt;
        $resource->updatedAt = $dto->updatedAt;

        return $resource;
    }
}
