<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Api\Provider;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Administration\Application\Query\IsSchoolDay\IsSchoolDayHandler;
use App\Administration\Application\Query\IsSchoolDay\IsSchoolDayQuery;
use App\Administration\Infrastructure\Api\Resource\CalendarResource;
use App\Administration\Infrastructure\Security\CalendarVoter;
use App\Administration\Infrastructure\Service\CurrentAcademicYearResolver;
use App\Shared\Infrastructure\Tenant\TenantContext;
use Override;

use function preg_match;

use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

/**
 * @implements ProviderInterface<CalendarResource>
 */
final readonly class IsSchoolDayProvider implements ProviderInterface
{
    public function __construct(
        private IsSchoolDayHandler $handler,
        private TenantContext $tenantContext,
        private AuthorizationCheckerInterface $authorizationChecker,
        private CurrentAcademicYearResolver $academicYearResolver,
    ) {
    }

    #[Override]
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): CalendarResource
    {
        if (!$this->authorizationChecker->isGranted(CalendarVoter::VIEW)) {
            throw new AccessDeniedHttpException('Vous n\'êtes pas autorisé à consulter le calendrier.');
        }

        if (!$this->tenantContext->hasTenant()) {
            throw new UnauthorizedHttpException('Bearer', 'Tenant non défini.');
        }

        /** @var string $rawAcademicYearId */
        $rawAcademicYearId = $uriVariables['academicYearId'];
        $academicYearId = $this->academicYearResolver->resolve($rawAcademicYearId);

        if ($academicYearId === null) {
            throw new NotFoundHttpException('Année scolaire non trouvée.');
        }

        /** @var string $date */
        $date = $uriVariables['date'];

        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $date) !== 1) {
            throw new BadRequestHttpException('La date doit être au format YYYY-MM-DD.');
        }

        [$y, $m, $d] = explode('-', $date);
        if (!checkdate((int) $m, (int) $d, (int) $y)) {
            throw new BadRequestHttpException('La date n\'existe pas dans le calendrier.');
        }

        $tenantId = (string) $this->tenantContext->getCurrentTenantId();

        $isSchoolDay = ($this->handler)(new IsSchoolDayQuery(
            tenantId: $tenantId,
            academicYearId: $academicYearId,
            date: $date,
        ));

        $resource = new CalendarResource();
        $resource->academicYearId = $academicYearId;
        $resource->isSchoolDay = $isSchoolDay;
        $resource->date = $date;

        return $resource;
    }
}
