<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Api\Provider;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Administration\Domain\Model\User\Role;
use App\Administration\Domain\Model\User\UserId;
use App\Administration\Infrastructure\Security\SecurityUser;
use App\Scolarite\Application\Port\PeriodFinder;
use App\Scolarite\Domain\Repository\StudentAverageRepository;
use App\Scolarite\Infrastructure\Api\Resource\StudentMyAveragesResource;
use App\Shared\Infrastructure\Tenant\TenantContext;
use DateTimeImmutable;

use function in_array;

use Override;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

/**
 * @implements ProviderInterface<StudentMyAveragesResource>
 */
final readonly class StudentMyAveragesProvider implements ProviderInterface
{
    public function __construct(
        private StudentAverageRepository $studentAverageRepository,
        private PeriodFinder $periodFinder,
        private TenantContext $tenantContext,
        private Security $security,
    ) {
    }

    #[Override]
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): StudentMyAveragesResource
    {
        if (!$this->tenantContext->hasTenant()) {
            throw new UnauthorizedHttpException('Bearer', 'Tenant non défini.');
        }

        $user = $this->security->getUser();

        if (!$user instanceof SecurityUser) {
            throw new UnauthorizedHttpException('Bearer', 'Authentification requise.');
        }

        if (!in_array(Role::ELEVE->value, $user->getRoles(), true)) {
            throw new AccessDeniedHttpException('Accès réservé aux élèves.');
        }

        $tenantId = $this->tenantContext->getCurrentTenantId();
        $studentId = UserId::fromString($user->userId());

        /** @var array<string, mixed> $filters */
        $filters = $context['filters'] ?? [];
        /** @var string|null $periodId */
        $periodId = $filters['periodId'] ?? null;

        // Auto-detect current period if not specified
        if ($periodId === null) {
            $periodInfo = $this->periodFinder->findForDate(new DateTimeImmutable(), $tenantId);

            if ($periodInfo !== null) {
                $periodId = $periodInfo->periodId;
            }
        }

        $resource = new StudentMyAveragesResource();
        $resource->studentId = $user->userId();
        $resource->periodId = $periodId;

        if ($periodId === null) {
            return $resource;
        }

        $resource->subjectAverages = $this->studentAverageRepository->findDetailedSubjectAveragesForStudent(
            $studentId,
            $periodId,
            $tenantId,
        );

        $resource->generalAverage = $this->studentAverageRepository->findGeneralAverageForStudent(
            $studentId,
            $periodId,
            $tenantId,
        );

        return $resource;
    }
}
