<?php

declare(strict_types=1);

namespace App\Mcp\Tool\Slot;

use App\Entity\Composant;
use App\Entity\ComposantPieceSlot;
use App\Entity\ComposantProductSlot;
use App\Entity\ComposantSubcomponentSlot;
use App\Entity\Piece;
use App\Entity\PieceProductSlot;
use App\Entity\Product;
use App\Mcp\Tool\McpToolHelper;
use Doctrine\ORM\EntityManagerInterface;
use Mcp\Capability\Attribute\McpTool;
use Mcp\Schema\Result\CallToolResult;
use Symfony\Bundle\SecurityBundle\Security;

#[McpTool(
    name: 'update_slots',
    description: 'Update selected entities on one or more slots. Each slot entry needs slotId, slotType, and the selected entity ID (or null to clear). Requires ROLE_GESTIONNAIRE.',
)]
class UpdateSlotsTool
{
    use McpToolHelper;

    public function __construct(
        private readonly EntityManagerInterface $em,
        private readonly Security $security,
    ) {}

    public function __invoke(array $slots): CallToolResult
    {
        $this->requireRole($this->security, 'ROLE_GESTIONNAIRE');

        $results = [];

        foreach ($slots as $entry) {
            $slotId   = $entry['slotId'] ?? null;
            $slotType = $entry['slotType'] ?? null;

            if (null === $slotId || null === $slotType) {
                $this->mcpError('validation', 'Each slot entry must have slotId and slotType.');
            }

            $results[] = match ($slotType) {
                'composant_piece'        => $this->updateComposantPieceSlot($slotId, $entry),
                'composant_product'      => $this->updateComposantProductSlot($slotId, $entry),
                'composant_subcomponent' => $this->updateComposantSubcomponentSlot($slotId, $entry),
                'piece_product'          => $this->updatePieceProductSlot($slotId, $entry),
                default                  => $this->mcpError('validation', "Unknown slotType '{$slotType}'."),
            };
        }

        $this->em->flush();

        return $this->jsonResponse([
            'updated' => $results,
            'total'   => count($results),
        ]);
    }

    private function updateComposantPieceSlot(string $slotId, array $entry): array
    {
        $slot = $this->em->getRepository(ComposantPieceSlot::class)->find($slotId);

        if (null === $slot) {
            $this->mcpError('not_found', "ComposantPieceSlot '{$slotId}' not found.");
        }

        $selectedPieceId = $entry['selectedPieceId'] ?? null;
        $selectedPiece   = null;

        if (null !== $selectedPieceId) {
            $selectedPiece = $this->em->getRepository(Piece::class)->find($selectedPieceId);

            if (null === $selectedPiece) {
                $this->mcpError('not_found', "Piece '{$selectedPieceId}' not found.");
            }
        }

        $slot->setSelectedPiece($selectedPiece);

        return [
            'slotId'             => $slot->getId(),
            'slotType'           => 'composant_piece',
            'selectedEntityId'   => $selectedPiece?->getId(),
            'selectedEntityName' => $selectedPiece?->getName(),
        ];
    }

    private function updateComposantProductSlot(string $slotId, array $entry): array
    {
        $slot = $this->em->getRepository(ComposantProductSlot::class)->find($slotId);

        if (null === $slot) {
            $this->mcpError('not_found', "ComposantProductSlot '{$slotId}' not found.");
        }

        $selectedProductId = $entry['selectedProductId'] ?? null;
        $selectedProduct   = null;

        if (null !== $selectedProductId) {
            $selectedProduct = $this->em->getRepository(Product::class)->find($selectedProductId);

            if (null === $selectedProduct) {
                $this->mcpError('not_found', "Product '{$selectedProductId}' not found.");
            }
        }

        $slot->setSelectedProduct($selectedProduct);

        return [
            'slotId'             => $slot->getId(),
            'slotType'           => 'composant_product',
            'selectedEntityId'   => $selectedProduct?->getId(),
            'selectedEntityName' => $selectedProduct?->getName(),
        ];
    }

    private function updateComposantSubcomponentSlot(string $slotId, array $entry): array
    {
        $slot = $this->em->getRepository(ComposantSubcomponentSlot::class)->find($slotId);

        if (null === $slot) {
            $this->mcpError('not_found', "ComposantSubcomponentSlot '{$slotId}' not found.");
        }

        $selectedComposantId = $entry['selectedComposantId'] ?? null;
        $selectedComposant   = null;

        if (null !== $selectedComposantId) {
            $selectedComposant = $this->em->getRepository(Composant::class)->find($selectedComposantId);

            if (null === $selectedComposant) {
                $this->mcpError('not_found', "Composant '{$selectedComposantId}' not found.");
            }
        }

        $slot->setSelectedComposant($selectedComposant);

        return [
            'slotId'             => $slot->getId(),
            'slotType'           => 'composant_subcomponent',
            'selectedEntityId'   => $selectedComposant?->getId(),
            'selectedEntityName' => $selectedComposant?->getName(),
        ];
    }

    private function updatePieceProductSlot(string $slotId, array $entry): array
    {
        $slot = $this->em->getRepository(PieceProductSlot::class)->find($slotId);

        if (null === $slot) {
            $this->mcpError('not_found', "PieceProductSlot '{$slotId}' not found.");
        }

        $selectedProductId = $entry['selectedProductId'] ?? null;
        $selectedProduct   = null;

        if (null !== $selectedProductId) {
            $selectedProduct = $this->em->getRepository(Product::class)->find($selectedProductId);

            if (null === $selectedProduct) {
                $this->mcpError('not_found', "Product '{$selectedProductId}' not found.");
            }
        }

        $slot->setSelectedProduct($selectedProduct);

        return [
            'slotId'             => $slot->getId(),
            'slotType'           => 'piece_product',
            'selectedEntityId'   => $selectedProduct?->getId(),
            'selectedEntityName' => $selectedProduct?->getName(),
        ];
    }
}
