<?php

declare(strict_types=1);

namespace App\Controller;

use App\Entity\Comment;
use App\Entity\Document;
use App\Repository\ComposantRepository;
use App\Repository\DocumentRepository;
use App\Repository\MachineRepository;
use App\Repository\PieceRepository;
use App\Repository\ProductRepository;
use App\Repository\SiteRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;

#[Route('/api/documents')]
class DocumentQueryController extends AbstractController
{
    public function __construct(
        private readonly DocumentRepository $documentRepository,
        private readonly SiteRepository $siteRepository,
        private readonly MachineRepository $machineRepository,
        private readonly ComposantRepository $composantRepository,
        private readonly PieceRepository $pieceRepository,
        private readonly ProductRepository $productRepository,
        private readonly EntityManagerInterface $em,
    ) {}

    #[Route('/site/{id}', name: 'documents_by_site', methods: ['GET'])]
    public function listBySite(string $id): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_VIEWER');

        $site = $this->siteRepository->find($id);
        if (!$site) {
            return $this->json(['success' => false, 'error' => 'Site not found.'], 404);
        }

        $documents = $this->documentRepository->findBy(['site' => $site]);

        return $this->json($this->normalizeDocuments($documents));
    }

    #[Route('/machine/{id}', name: 'documents_by_machine', methods: ['GET'])]
    public function listByMachine(string $id): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_VIEWER');

        $machine = $this->machineRepository->find($id);
        if (!$machine) {
            return $this->json(['success' => false, 'error' => 'Machine not found.'], 404);
        }

        $documents = $this->documentRepository->findBy(['machine' => $machine]);

        return $this->json($this->normalizeDocuments($documents));
    }

    #[Route('/composant/{id}', name: 'documents_by_composant', methods: ['GET'])]
    public function listByComposant(string $id): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_VIEWER');

        $composant = $this->composantRepository->find($id);
        if (!$composant) {
            return $this->json(['success' => false, 'error' => 'Composant not found.'], 404);
        }

        $documents = $this->documentRepository->findBy(['composant' => $composant]);

        return $this->json($this->normalizeDocuments($documents));
    }

    #[Route('/piece/{id}', name: 'documents_by_piece', methods: ['GET'])]
    public function listByPiece(string $id): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_VIEWER');

        $piece = $this->pieceRepository->find($id);
        if (!$piece) {
            return $this->json(['success' => false, 'error' => 'Piece not found.'], 404);
        }

        $documents = $this->documentRepository->findBy(['piece' => $piece]);

        return $this->json($this->normalizeDocuments($documents));
    }

    #[Route('/product/{id}', name: 'documents_by_product', methods: ['GET'])]
    public function listByProduct(string $id): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_VIEWER');

        $product = $this->productRepository->find($id);
        if (!$product) {
            return $this->json(['success' => false, 'error' => 'Product not found.'], 404);
        }

        $documents = $this->documentRepository->findBy(['product' => $product]);

        return $this->json($this->normalizeDocuments($documents));
    }

    #[Route('/comment/{id}', name: 'documents_by_comment', methods: ['GET'])]
    public function listByComment(string $id): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_VIEWER');

        $comment = $this->em->find(Comment::class, $id);
        if (!$comment) {
            return $this->json(['success' => false, 'error' => 'Comment not found.'], 404);
        }

        $documents = $this->documentRepository->findBy(['comment' => $comment]);

        return $this->json($this->normalizeDocuments($documents));
    }

    /**
     * @param Document[] $documents
     */
    private function normalizeDocuments(array $documents): array
    {
        return array_map(static function (Document $document): array {
            return [
                'id'          => $document->getId(),
                'name'        => $document->getName(),
                'filename'    => $document->getFilename(),
                'fileUrl'     => '/api/documents/'.$document->getId().'/file',
                'downloadUrl' => '/api/documents/'.$document->getId().'/download',
                'mimeType'    => $document->getMimeType(),
                'size'        => $document->getSize(),
                'siteId'      => $document->getSite()?->getId(),
                'machineId'   => $document->getMachine()?->getId(),
                'composantId' => $document->getComposant()?->getId(),
                'pieceId'     => $document->getPiece()?->getId(),
                'productId'   => $document->getProduct()?->getId(),
                'commentId'   => $document->getComment()?->getId(),
                'type'        => $document->getType()->value,
                'createdAt'   => $document->getCreatedAt()->format(DATE_ATOM),
                'updatedAt'   => $document->getUpdatedAt()->format(DATE_ATOM),
            ];
        }, $documents);
    }
}
