<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Api\Resource;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use App\Administration\Application\Query\GetParentInvitations\ParentInvitationDto;
use App\Administration\Domain\Model\Invitation\ParentInvitation;
use App\Administration\Infrastructure\Api\Processor\ActivateParentInvitationProcessor;
use App\Administration\Infrastructure\Api\Processor\ResendParentInvitationProcessor;
use App\Administration\Infrastructure\Api\Processor\SendParentInvitationProcessor;
use App\Administration\Infrastructure\Api\Provider\ParentInvitationCollectionProvider;
use DateTimeImmutable;
use Symfony\Component\Validator\Constraints as Assert;

#[ApiResource(
    shortName: 'ParentInvitation',
    operations: [
        new GetCollection(
            uriTemplate: '/parent-invitations',
            provider: ParentInvitationCollectionProvider::class,
            name: 'get_parent_invitations',
        ),
        new Post(
            uriTemplate: '/parent-invitations',
            processor: SendParentInvitationProcessor::class,
            validationContext: ['groups' => ['Default', 'create']],
            name: 'send_parent_invitation',
        ),
        new Post(
            uriTemplate: '/parent-invitations/{id}/resend',
            processor: ResendParentInvitationProcessor::class,
            name: 'resend_parent_invitation',
        ),
        new Post(
            uriTemplate: '/parent-invitations/activate',
            processor: ActivateParentInvitationProcessor::class,
            output: ActivateParentInvitationOutput::class,
            validationContext: ['groups' => ['Default', 'activate']],
            name: 'activate_parent_invitation',
        ),
    ],
)]
final class ParentInvitationResource
{
    #[ApiProperty(identifier: true)]
    public ?string $id = null;

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

    #[Assert\NotBlank(message: 'L\'email du parent est requis.', groups: ['create'])]
    #[Assert\Email(message: 'L\'email n\'est pas valide.')]
    public ?string $parentEmail = null;

    public ?string $status = null;

    public ?DateTimeImmutable $createdAt = null;

    public ?DateTimeImmutable $expiresAt = null;

    public ?DateTimeImmutable $sentAt = null;

    public ?DateTimeImmutable $activatedAt = null;

    public ?string $activatedUserId = null;

    public ?string $studentFirstName = null;

    public ?string $studentLastName = null;

    #[ApiProperty(readable: false, writable: true)]
    #[Assert\NotBlank(message: 'Le code d\'invitation est requis.', groups: ['activate'])]
    public ?string $code = null;

    #[ApiProperty(readable: false, writable: true)]
    #[Assert\NotBlank(message: 'Le prénom est requis.', groups: ['activate'])]
    #[Assert\Length(min: 2, max: 100, minMessage: 'Le prénom doit contenir au moins {{ limit }} caractères.', maxMessage: 'Le prénom ne doit pas dépasser {{ limit }} caractères.', groups: ['activate'])]
    public ?string $firstName = null;

    #[ApiProperty(readable: false, writable: true)]
    #[Assert\NotBlank(message: 'Le nom est requis.', groups: ['activate'])]
    #[Assert\Length(min: 2, max: 100, minMessage: 'Le nom doit contenir au moins {{ limit }} caractères.', maxMessage: 'Le nom ne doit pas dépasser {{ limit }} caractères.', groups: ['activate'])]
    public ?string $lastName = null;

    #[ApiProperty(readable: false, writable: true)]
    #[Assert\NotBlank(message: 'Le mot de passe est requis.', groups: ['activate'])]
    #[Assert\Length(min: 8, minMessage: 'Le mot de passe doit contenir au moins {{ limit }} caractères.', groups: ['activate'])]
    #[Assert\Regex(pattern: '/[A-Z]/', message: 'Le mot de passe doit contenir au moins une majuscule.', groups: ['activate'])]
    #[Assert\Regex(pattern: '/[a-z]/', message: 'Le mot de passe doit contenir au moins une minuscule.', groups: ['activate'])]
    #[Assert\Regex(pattern: '/[0-9]/', message: 'Le mot de passe doit contenir au moins un chiffre.', groups: ['activate'])]
    #[Assert\Regex(pattern: '/[^A-Za-z0-9]/', message: 'Le mot de passe doit contenir au moins un caractère spécial.', groups: ['activate'])]
    public ?string $password = null;

    public static function fromDomain(ParentInvitation $invitation): self
    {
        $resource = new self();
        $resource->id = (string) $invitation->id;
        $resource->studentId = (string) $invitation->studentId;
        $resource->parentEmail = (string) $invitation->parentEmail;
        $resource->status = $invitation->status->value;
        $resource->createdAt = $invitation->createdAt;
        $resource->expiresAt = $invitation->expiresAt;
        $resource->sentAt = $invitation->sentAt;
        $resource->activatedAt = $invitation->activatedAt;
        $resource->activatedUserId = $invitation->activatedUserId !== null ? (string) $invitation->activatedUserId : null;

        return $resource;
    }

    public static function fromDto(ParentInvitationDto $dto): self
    {
        $resource = new self();
        $resource->id = $dto->id;
        $resource->studentId = $dto->studentId;
        $resource->parentEmail = $dto->parentEmail;
        $resource->status = $dto->status;
        $resource->createdAt = $dto->createdAt;
        $resource->expiresAt = $dto->expiresAt;
        $resource->sentAt = $dto->sentAt;
        $resource->activatedAt = $dto->activatedAt;
        $resource->activatedUserId = $dto->activatedUserId;
        $resource->studentFirstName = $dto->studentFirstName;
        $resource->studentLastName = $dto->studentLastName;

        return $resource;
    }
}
