<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Api\Provider;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Administration\Domain\Model\SchoolClass\ClassId;
use App\Administration\Domain\Model\User\UserId;
use App\Administration\Domain\Repository\ClassRepository;
use App\Administration\Domain\Repository\SubjectRepository;
use App\Administration\Infrastructure\Security\SecurityUser;
use App\Scolarite\Domain\Model\Homework\Homework;
use App\Scolarite\Domain\Repository\HomeworkRepository;
use App\Scolarite\Domain\Repository\HomeworkRuleExceptionRepository;
use App\Scolarite\Infrastructure\Api\Resource\HomeworkResource;
use App\Shared\Infrastructure\Tenant\TenantContext;

use function array_filter;
use function array_map;
use function array_values;
use function is_string;

use Override;
use Ramsey\Uuid\Exception\InvalidUuidStringException;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

/**
 * @implements ProviderInterface<HomeworkResource>
 */
final readonly class HomeworkCollectionProvider implements ProviderInterface
{
    public function __construct(
        private HomeworkRepository $homeworkRepository,
        private HomeworkRuleExceptionRepository $exceptionRepository,
        private TenantContext $tenantContext,
        private Security $security,
        private ClassRepository $classRepository,
        private SubjectRepository $subjectRepository,
    ) {
    }

    /** @return array<HomeworkResource> */
    #[Override]
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
    {
        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.');
        }

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

        $homeworks = $this->homeworkRepository->findByTeacher($teacherId, $tenantId);

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

        if (is_string($classIdFilter) && $classIdFilter !== '') {
            try {
                $filterClassId = ClassId::fromString($classIdFilter);
            } catch (InvalidUuidStringException $e) {
                throw new BadRequestHttpException('UUID de classe invalide : ' . $e->getMessage());
            }

            $homeworks = array_values(array_filter(
                $homeworks,
                static fn (Homework $h): bool => $h->classId->equals($filterClassId),
            ));
        }

        $allExceptions = $this->exceptionRepository->findByTenant($tenantId);
        $exceptionsByHomework = [];

        foreach ($allExceptions as $exception) {
            $hwId = (string) $exception->homeworkId;

            if (!isset($exceptionsByHomework[$hwId])) {
                $exceptionsByHomework[$hwId] = $exception;
            }
        }

        return array_map(fn (Homework $homework) => HomeworkResource::fromDomain(
            $homework,
            $this->resolveClassName($homework),
            $this->resolveSubjectName($homework),
            $exceptionsByHomework[(string) $homework->id] ?? null,
        ), $homeworks);
    }

    private function resolveClassName(Homework $homework): ?string
    {
        $class = $this->classRepository->findById($homework->classId);

        return $class !== null ? (string) $class->name : null;
    }

    private function resolveSubjectName(Homework $homework): ?string
    {
        $subject = $this->subjectRepository->findById($homework->subjectId);

        return $subject !== null ? (string) $subject->name : null;
    }
}
