<?php

declare(strict_types=1);

namespace Butschster\ContextGenerator\McpServer\Action\Tools\Prompts;

use Butschster\ContextGenerator\Lib\Variable\VariableResolver;
use Butschster\ContextGenerator\McpServer\Prompt\PromptProviderInterface;
use Butschster\ContextGenerator\McpServer\Action\Tools\Prompts\Dto\GetPromptRequest;
use Butschster\ContextGenerator\McpServer\Attribute\InputSchema;
use Butschster\ContextGenerator\McpServer\Attribute\Tool;
use Butschster\ContextGenerator\McpServer\Action\ToolResult;
use Butschster\ContextGenerator\McpServer\Routing\Attribute\Post;
use PhpMcp\Schema\Content\PromptMessage;
use PhpMcp\Schema\Content\TextContent;
use PhpMcp\Schema\Result\CallToolResult;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;

#[Tool(
    name: 'prompt-get',
    description: 'Use this tool when you already know the specific prompt ID and need to retrieve its full content. First use prompts-list tool to discover available prompts, then use this tool to get the detailed content of a specific prompt you need. Requires the prompt ID as a parameter.',
    title: 'Get Prompt by ID',
)]
#[InputSchema(class: GetPromptRequest::class)]
final readonly class GetPromptToolAction
{
    public function __construct(
        private LoggerInterface $logger,
        private PromptProviderInterface $prompts,
        private VariableResolver $variables,
    ) {}

    #[Post(path: '/tools/call/prompt-get', name: 'tools.prompts.get')]
    public function __invoke(GetPromptRequest $request, ServerRequestInterface $serverRequest): CallToolResult
    {
        $this->logger->info('Getting prompt via tool action');

        // Get prompt ID from request
        $id = $request->id;

        if (empty($id)) {
            return ToolResult::error('Missing prompt ID parameter');
        }

        try {
            // Check if prompt exists
            if (!$this->prompts->has($id)) {
                return ToolResult::error(\sprintf("Prompt with ID '%s' not found", $id));
            }

            // Get prompt and process messages
            $prompt = $this->prompts->get($id);
            $messages = $this->processMessageTemplates($prompt->messages, $serverRequest->getAttributes());

            // Format the messages for return
            $formattedMessages = [];
            foreach ($messages as $message) {
                $content = $message->content;
                $formattedMessages[] = [
                    'role' => $message->role->value,
                    'content' => $content instanceof TextContent ? $content->text : 'Non-text content',
                ];
            }

            return ToolResult::success([
                'id' => $id,
                'description' => $prompt->prompt->description,
                'messages' => $formattedMessages,
            ]);
        } catch (\Throwable $e) {
            $this->logger->error('Error getting prompt', [
                'id' => $id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return ToolResult::error($e->getMessage());
        }
    }

    /**
     * Processes message templates with the given arguments.
     *
     * @param array<PromptMessage> $messages The messages to process
     * @param array $arguments The arguments to use
     * @return array The processed messages
     */
    private function processMessageTemplates(array $messages, array $arguments): array
    {
        $arguments = \array_combine(
            \array_map(static fn($key) => '{{' . $key . '}}', \array_keys($arguments)),
            \array_values($arguments),
        );
        $variables = $this->variables;

        return \array_map(static function ($message) use ($variables, $arguments) {
            $content = $message->content;

            if ($content instanceof TextContent) {
                $text = \strtr($content->text, $arguments);
                $text = $variables->resolve($text);

                $content = new TextContent($text);
            }

            return new PromptMessage(
                role: $message->role,
                content: $content,
            );
        }, $messages);
    }
}
