<?php

declare(strict_types=1);

namespace App\Module\Absence\Infrastructure\ApiPlatform\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Module\Absence\Domain\Entity\AbsenceRequest;
use App\Module\Absence\Domain\Repository\AbsenceRequestRepositoryInterface;
use App\Shared\Domain\Contract\UserInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\SecurityBundle\Security;

/**
 * @implements ProviderInterface<AbsenceRequest>
 */
final readonly class AbsenceRequestProvider implements ProviderInterface
{
    public function __construct(
        private EntityManagerInterface $entityManager,
        private AbsenceRequestRepositoryInterface $requestRepository,
        private Security $security,
    ) {}

    public function provide(Operation $operation, array $uriVariables = [], array $context = []): AbsenceRequest|array|null
    {
        $user = $this->security->getUser();
        assert($user instanceof UserInterface);

        $isAdmin = $this->security->isGranted('ROLE_ADMIN');

        // Single item: owner or admin only
        if (isset($uriVariables['id'])) {
            $request = $this->requestRepository->findById((int) $uriVariables['id']);
            if (null === $request) {
                return null;
            }
            if (!$isAdmin && $request->getUser() !== $user) {
                return null;
            }

            return $request;
        }

        $qb = $this->entityManager->getRepository(AbsenceRequest::class)
            ->createQueryBuilder('a')
            ->orderBy('a.createdAt', 'DESC')
        ;

        if (!$isAdmin) {
            $qb->andWhere('a.user = :user')->setParameter('user', $user);
        }

        $filters = $context['filters'] ?? [];

        if (isset($filters['status'])) {
            $qb->andWhere('a.status = :status')->setParameter('status', $filters['status']);
        }
        if (isset($filters['type'])) {
            $qb->andWhere('a.type = :type')->setParameter('type', $filters['type']);
        }
        if (isset($filters['year']) && is_numeric($filters['year'])) {
            $year = (int) $filters['year'];
            $qb->andWhere('a.startDate <= :yearEnd')
                ->andWhere('a.endDate >= :yearStart')
                ->setParameter('yearStart', sprintf('%d-01-01', $year))
                ->setParameter('yearEnd', sprintf('%d-12-31', $year))
            ;
        }
        if ($isAdmin && isset($filters['user'])) {
            $qb->andWhere('a.user = :filterUser')
                ->setParameter('filterUser', self::extractId($filters['user']))
            ;
        }

        return $qb->getQuery()->getResult();
    }

    private static function extractId(string $value): int
    {
        return is_numeric($value) ? (int) $value : (int) basename($value);
    }
}
