<?php

declare(strict_types=1);

namespace App\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Entity\Document;
use App\Enum\DocumentType;
use App\Service\DocumentStorageService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

final class DocumentUploadProcessor implements ProcessorInterface
{
    public function __construct(
        #[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')]
        private readonly ProcessorInterface $decorated,
        private readonly RequestStack $requestStack,
        private readonly DocumentStorageService $storageService,
        private readonly EntityManagerInterface $em,
    ) {}

    /**
     * @param array<string, mixed> $uriVariables
     * @param array<string, mixed> $context
     */
    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
    {
        $request = $this->requestStack->getCurrentRequest();
        if (null === $request) {
            throw new BadRequestHttpException('No request available.');
        }

        $contentType = $request->headers->get('Content-Type', '');

        // Multipart/form-data → file upload
        if (str_contains($contentType, 'multipart/form-data')) {
            return $this->handleMultipartUpload($operation, $uriVariables, $context, $request);
        }

        // Fallback to default processor for legacy JSON/Base64 requests
        if (!$data instanceof Document) {
            return $this->decorated->process($data, $operation, $uriVariables, $context);
        }

        return $this->decorated->process($data, $operation, $uriVariables, $context);
    }

    private function handleMultipartUpload(
        Operation $operation,
        array $uriVariables,
        array $context,
        Request $request,
    ): Document {
        /** @var null|UploadedFile $file */
        $file = $request->files->get('file');
        if (null === $file || !$file->isValid()) {
            throw new BadRequestHttpException('A valid file is required in the "file" field.');
        }

        $allowedMimeTypes = [
            'application/pdf',
            'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/bmp',
            'text/plain', 'text/csv',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'application/msword', 'application/vnd.ms-excel',
            'application/zip',
        ];
        $detectedMime = $file->getMimeType() ?: 'application/octet-stream';
        if (!in_array($detectedMime, $allowedMimeTypes, true)) {
            throw new BadRequestHttpException(sprintf('Type de fichier non autorisé : %s', $detectedMime));
        }

        $document = new Document();

        // Metadata from form fields
        $name     = $request->request->get('name', $file->getClientOriginalName());
        $filename = $file->getClientOriginalName();
        $mimeType = $file->getMimeType() ?: $request->request->get('mimeType', 'application/octet-stream');
        $size     = $file->getSize();

        $document->setName($name);
        $document->setFilename($filename);
        $document->setMimeType($mimeType);
        $document->setSize((int) $size);

        $typeValue = $request->request->get('type', 'documentation');
        $docType   = DocumentType::tryFrom($typeValue) ?? DocumentType::DOCUMENTATION;
        $document->setType($docType);

        // Handle entity relations from form fields
        $this->setRelationsFromRequest($document, $request);

        // Generate CUID early so we can use it for the filename on disk
        $documentId = 'cl'.bin2hex(random_bytes(12));
        $document->setId($documentId);

        // Store file on disk
        $extension    = $this->storageService->extensionFromFilename($filename);
        $relativePath = $this->storageService->storeFromPath(
            $file->getPathname(),
            $documentId,
            $extension,
        );
        $document->setPath($relativePath);

        // Persist via decorated processor (triggers prePersist for timestamps)
        return $this->decorated->process($document, $operation, $uriVariables, $context);
    }

    private function setRelationsFromRequest(Document $document, Request $request): void
    {
        $relationMap = [
            'machineId'   => 'Machine',
            'composantId' => 'Composant',
            'pieceId'     => 'Piece',
            'productId'   => 'Product',
            'siteId'      => 'Site',
            'commentId'   => 'Comment',
        ];

        foreach ($relationMap as $field => $entityName) {
            $value = $request->request->get($field);
            if (!$value) {
                continue;
            }

            // Accept both raw ID and IRI format
            $id = $value;
            if (str_contains($value, '/')) {
                $parts = explode('/', rtrim($value, '/'));
                $id    = end($parts);
            }

            $entityClass = 'App\Entity\\'.$entityName;
            $entity      = $this->em->getReference($entityClass, $id);
            $setter      = 'set'.$entityName;
            $document->{$setter}($entity);
        }
    }
}
