<?php

declare(strict_types=1);

namespace App\Module\Absence\Infrastructure\Controller;

use App\Module\Absence\Domain\Repository\AbsenceRequestRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Uid\Uuid;

/**
 * Uploads a justification file (PDF / image) for an absence request. The owner
 * or an admin may upload; the server-detected MIME type is validated.
 */
class AbsenceJustificationUploadController extends AbstractController
{
    private const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB

    private const MIME_TO_EXTENSION = [
        'image/jpeg'      => 'jpg',
        'image/png'       => 'png',
        'image/webp'      => 'webp',
        'application/pdf' => 'pdf',
    ];

    public function __construct(
        private readonly EntityManagerInterface $entityManager,
        private readonly AbsenceRequestRepositoryInterface $requestRepository,
        private readonly Security $security,
        private readonly string $uploadDir,
    ) {}

    #[Route('/api/absence_requests/{id}/justificatif', name: 'absence_justification_upload', methods: ['POST'], priority: 1)]
    #[IsGranted('ROLE_USER')]
    public function __invoke(int $id, Request $request): JsonResponse
    {
        $absence = $this->requestRepository->findById($id);
        if (null === $absence) {
            throw new NotFoundHttpException('Absence request not found.');
        }

        if (!$this->security->isGranted('ROLE_ADMIN') && $absence->getUser() !== $this->security->getUser()) {
            throw new AccessDeniedHttpException('You can only attach a file to your own request.');
        }

        $file = $request->files->get('file');
        if (null === $file || !$file->isValid()) {
            throw new BadRequestHttpException('No valid file uploaded.');
        }
        if ($file->getSize() > self::MAX_FILE_SIZE) {
            throw new BadRequestHttpException('File size exceeds 10 MB limit.');
        }

        $mimeType = $file->getMimeType() ?: 'application/octet-stream';
        if (!isset(self::MIME_TO_EXTENSION[$mimeType])) {
            throw new BadRequestHttpException(sprintf('File type "%s" is not allowed (PDF or image only).', $mimeType));
        }

        $fileName = Uuid::v4()->toRfc4122().'.'.self::MIME_TO_EXTENSION[$mimeType];

        if (!is_dir($this->uploadDir)) {
            mkdir($this->uploadDir, 0o775, true);
        }

        // Remove a previously uploaded file if any
        $previous = $absence->getJustificationFileName();
        if (null !== $previous && file_exists($this->uploadDir.'/'.$previous)) {
            unlink($this->uploadDir.'/'.$previous);
        }

        $file->move($this->uploadDir, $fileName);

        $absence->setJustificationFileName($fileName);
        $this->entityManager->flush();

        return $this->json($absence, context: ['groups' => ['absence_request:read']]);
    }
}
