<?php

declare(strict_types=1);

namespace App\Controller;

use App\Repository\ComposantRepository;
use App\Repository\MachineRepository;
use App\Repository\PieceRepository;
use App\Repository\ProductRepository;
use App\Service\EntityVersionService;
use InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

final class EntityVersionController extends AbstractController
{
    /** @var array<string, array{repo: object, label: string}> */
    private readonly array $entityConfig;

    public function __construct(
        MachineRepository $machines,
        PieceRepository $pieces,
        ComposantRepository $composants,
        ProductRepository $products,
        private readonly EntityVersionService $versionService,
    ) {
        $this->entityConfig = [
            'machine'   => ['repo' => $machines, 'label' => 'Machine introuvable.'],
            'piece'     => ['repo' => $pieces, 'label' => 'Pièce introuvable.'],
            'composant' => ['repo' => $composants, 'label' => 'Composant introuvable.'],
            'product'   => ['repo' => $products, 'label' => 'Produit introuvable.'],
        ];
    }

    // ── Versions list ───────────────────────────────────────────────

    #[Route('/api/machines/{id}/versions', name: 'api_machine_versions', methods: ['GET'])]
    public function machineVersions(string $id): JsonResponse
    {
        return $this->listVersions('machine', $id);
    }

    #[Route('/api/composants/{id}/versions', name: 'api_composant_versions', methods: ['GET'])]
    public function composantVersions(string $id): JsonResponse
    {
        return $this->listVersions('composant', $id);
    }

    #[Route('/api/pieces/{id}/versions', name: 'api_piece_versions', methods: ['GET'])]
    public function pieceVersions(string $id): JsonResponse
    {
        return $this->listVersions('piece', $id);
    }

    #[Route('/api/products/{id}/versions', name: 'api_product_versions', methods: ['GET'])]
    public function productVersions(string $id): JsonResponse
    {
        return $this->listVersions('product', $id);
    }

    // ── Preview ─────────────────────────────────────────────────────

    #[Route('/api/machines/{id}/versions/{version}/preview', name: 'api_machine_version_preview', methods: ['GET'])]
    public function machineVersionPreview(string $id, int $version): JsonResponse
    {
        return $this->preview('machine', $id, $version);
    }

    #[Route('/api/composants/{id}/versions/{version}/preview', name: 'api_composant_version_preview', methods: ['GET'])]
    public function composantVersionPreview(string $id, int $version): JsonResponse
    {
        return $this->preview('composant', $id, $version);
    }

    #[Route('/api/pieces/{id}/versions/{version}/preview', name: 'api_piece_version_preview', methods: ['GET'])]
    public function pieceVersionPreview(string $id, int $version): JsonResponse
    {
        return $this->preview('piece', $id, $version);
    }

    #[Route('/api/products/{id}/versions/{version}/preview', name: 'api_product_version_preview', methods: ['GET'])]
    public function productVersionPreview(string $id, int $version): JsonResponse
    {
        return $this->preview('product', $id, $version);
    }

    // ── Restore ─────────────────────────────────────────────────────

    #[Route('/api/machines/{id}/versions/{version}/restore', name: 'api_machine_version_restore', methods: ['POST'])]
    public function machineVersionRestore(string $id, int $version): JsonResponse
    {
        return $this->restoreVersion('machine', $id, $version);
    }

    #[Route('/api/composants/{id}/versions/{version}/restore', name: 'api_composant_version_restore', methods: ['POST'])]
    public function composantVersionRestore(string $id, int $version): JsonResponse
    {
        return $this->restoreVersion('composant', $id, $version);
    }

    #[Route('/api/pieces/{id}/versions/{version}/restore', name: 'api_piece_version_restore', methods: ['POST'])]
    public function pieceVersionRestore(string $id, int $version): JsonResponse
    {
        return $this->restoreVersion('piece', $id, $version);
    }

    #[Route('/api/products/{id}/versions/{version}/restore', name: 'api_product_version_restore', methods: ['POST'])]
    public function productVersionRestore(string $id, int $version): JsonResponse
    {
        return $this->restoreVersion('product', $id, $version);
    }

    // ── Private helpers ─────────────────────────────────────────────

    private function listVersions(string $entityType, string $entityId): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_VIEWER');

        $config = $this->entityConfig[$entityType];
        if (!$config['repo']->find($entityId)) {
            return new JsonResponse(['message' => $config['label']], Response::HTTP_NOT_FOUND);
        }

        return new JsonResponse($this->versionService->getVersions($entityType, $entityId));
    }

    private function preview(string $entityType, string $entityId, int $version): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_GESTIONNAIRE');

        try {
            $result = $this->versionService->getRestorePreview($entityType, $entityId, $version);

            return new JsonResponse($result);
        } catch (InvalidArgumentException $e) {
            return new JsonResponse(['message' => $e->getMessage()], Response::HTTP_NOT_FOUND);
        }
    }

    private function restoreVersion(string $entityType, string $entityId, int $version): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_GESTIONNAIRE');

        try {
            $result = $this->versionService->restore($entityType, $entityId, $version);

            return new JsonResponse($result);
        } catch (InvalidArgumentException $e) {
            return new JsonResponse(['message' => $e->getMessage()], Response::HTTP_NOT_FOUND);
        }
    }
}
