<?php

declare(strict_types=1);

namespace Butschster\ContextGenerator\McpServer\Prompt\Console;

use Butschster\ContextGenerator\Application\AppScope;
use Butschster\ContextGenerator\Config\ConfigurationProvider;
use Butschster\ContextGenerator\Config\Exception\ConfigLoaderException;
use Butschster\ContextGenerator\Console\BaseCommand;
use Butschster\ContextGenerator\Console\Renderer\Style;
use Butschster\ContextGenerator\DirectoriesInterface;
use Butschster\ContextGenerator\McpServer\Prompt\Extension\PromptDefinition;
use Butschster\ContextGenerator\McpServer\Prompt\PromptProviderInterface;
use Butschster\ContextGenerator\McpServer\Prompt\PromptType;
use PhpMcp\Schema\Prompt;
use Spiral\Console\Attribute\Argument;
use Spiral\Console\Attribute\Option;
use Spiral\Core\Container;
use Spiral\Core\Scope;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Helper\TableCellStyle;

#[AsCommand(
    name: 'prompt:show',
    description: 'Show detailed information about a specific prompt',
)]
final class ShowPromptCommand extends BaseCommand
{
    #[Argument(
        name: 'id',
        description: 'The ID of the prompt to display',
    )]
    protected string $promptId;

    #[Option(
        name: 'config-file',
        shortcut: 'c',
        description: 'Path to configuration file (absolute or relative to current directory).',
    )]
    protected ?string $configPath = null;

    #[Option(
        name: 'with-messages',
        shortcut: 'm',
        description: 'Show the full message content',
    )]
    protected bool $withMessages = false;

    public function __invoke(Container $container, DirectoriesInterface $dirs): int
    {
        return $container->runScope(
            bindings: new Scope(
                name: AppScope::Compiler,
                bindings: [
                    DirectoriesInterface::class => $dirs->determineRootPath($this->configPath),
                ],
            ),
            scope: function (
                ConfigurationProvider $configProvider,
                PromptProviderInterface $promptProvider,
            ) {
                try {
                    // Get the appropriate loader based on options provided
                    if ($this->configPath !== null) {
                        $this->logger->info(\sprintf('Loading configuration from %s...', $this->configPath));
                        $loader = $configProvider->fromPath($this->configPath);
                    } else {
                        $this->logger->info('Loading configuration from default location...');
                        $loader = $configProvider->fromDefaultLocation();
                    }
                } catch (ConfigLoaderException $e) {
                    $this->logger->error('Failed to load configuration', [
                        'error' => $e->getMessage(),
                    ]);

                    $this->output->error(\sprintf('Failed to load configuration: %s', $e->getMessage()));

                    return Command::FAILURE;
                }

                // Load configuration to make sure all prompts are properly registered
                $loader->load();

                // Check if prompt exists
                if (!$promptProvider->has($this->promptId)) {
                    $this->output->error(\sprintf('Prompt with ID "%s" not found.', $this->promptId));

                    // Suggest similar prompts
                    $this->suggestSimilarPrompts($promptProvider);

                    return Command::FAILURE;
                }

                // Get the prompt
                $prompt = $promptProvider->get($this->promptId);

                // Display prompt details
                return $this->displayPromptDetails($prompt);
            },
        );
    }

    /**
     * Displays detailed information about a prompt.
     */
    private function displayPromptDetails(PromptDefinition $prompt): int
    {
        $this->output->title(\sprintf('Prompt: %s', $prompt->id));

        // Basic information table
        $this->displayBasicInfo($prompt);

        // Arguments table
        if (!empty($prompt->prompt->arguments)) {
            $this->displayArguments($prompt->prompt);
        }

        // Messages
        if ($this->withMessages && !empty($prompt->messages)) {
            $this->displayMessages($prompt);
        }

        return Command::SUCCESS;
    }

    /**
     * Displays basic prompt information.
     */
    private function displayBasicInfo(PromptDefinition $prompt): void
    {
        $this->output->writeln('');
        $this->output->writeln(Style::section('Basic Information'));

        $table = new Table($this->output);
        $table->setStyle('box');

        $rows = [
            ['ID', $prompt->id],
            ['Type', $this->formatPromptType($prompt->type)],
        ];

        if ($prompt->prompt->description !== null) {
            $rows[] = ['Description', $prompt->prompt->description];
        }

        if (!empty($prompt->tags)) {
            $rows[] = ['Tags', \implode(', ', $prompt->tags)];
        }

        $rows[] = ['Messages', \count($prompt->messages)];
        $rows[] = ['Arguments', \count($prompt->prompt->arguments)];
        $rows[] = ['Extensions', \count($prompt->extensions)];

        foreach ($rows as $row) {
            $table->addRow([
                new TableCell($row[0], ['style' => new TableCellStyle(['fg' => 'yellow'])]),
                $row[1],
            ]);
        }

        $table->render();
    }

    /**
     * Displays prompt arguments.
     */
    private function displayArguments(Prompt $prompt): void
    {
        $this->output->writeln('');
        $this->output->writeln(Style::section('Arguments'));

        $table = new Table($this->output);
        $table->setHeaders(['Name', 'Required', 'Description']);
        $table->setStyle('box');

        foreach ($prompt->arguments as $arg) {
            $table->addRow([
                new TableCell($arg->name, ['style' => new TableCellStyle(['fg' => 'cyan'])]),
                $arg->required ? Style::success('Yes') : Style::muted('No'),
                $arg->description ?? Style::muted('(no description)'),
            ]);
        }

        $table->render();
    }

    /**
     * Displays prompt messages.
     */
    private function displayMessages(PromptDefinition $prompt): void
    {
        $this->output->writeln('');
        $this->output->writeln(Style::section('Messages'));

        foreach ($prompt->messages as $index => $message) {
            $index = (int) $index; // Ensure index is an integer for display
            $this->output->writeln('');
            $this->output->writeln(
                \sprintf('  %s. %s', $index + 1, Style::property('Role:') . ' ' . Style::value($message->role->value)),
            );

            // Show content preview (first few lines)
            /** @psalm-suppress UndefinedPropertyFetch */
            $content = $message->content->text;
            $lines = \explode("\n", $content);

            $this->output->writeln('     ' . Style::property('Content:'));

            // Show first 10 lines or all if less
            $displayLines = \array_slice($lines, 0, 10);
            foreach ($displayLines as $line) {
                $this->output->writeln('       ' . Style::muted($line));
            }

            // Show truncation indicator if there are more lines
            if (\count($lines) > 10) {
                $this->output->writeln('       ' . Style::muted(\sprintf('... (%d more lines)', \count($lines) - 10)));
            }

            $this->output->writeln('');
            $this->output->writeln('     ' . Style::property('Statistics:'));
            $this->output->writeln(\sprintf('       • Lines: %s', Style::count(\count($lines))));
            $this->output->writeln(\sprintf('       • Characters: %s', Style::count(\strlen($content))));
            $this->output->writeln(\sprintf('       • Words: %s', Style::count(\str_word_count($content))));
        }
    }

    /**
     * Suggests similar prompts when the requested prompt is not found.
     */
    private function suggestSimilarPrompts(PromptProviderInterface $promptProvider): void
    {
        $allPrompts = $promptProvider->all();

        if (empty($allPrompts)) {
            $this->output->writeln('No prompts are available.');
            return;
        }

        // Find prompts with similar IDs (simple string similarity)
        $suggestions = [];
        foreach ($allPrompts as $id => $_prompt) {
            $similarity = 0;
            \similar_text($this->promptId, $id, $similarity);
            if ($similarity > 30) { // 30% similarity threshold
                $suggestions[] = ['id' => $id, 'similarity' => $similarity];
            }
        }

        // Sort by similarity
        \usort($suggestions, static fn($a, $b) => $b['similarity'] <=> $a['similarity']);

        if (!empty($suggestions)) {
            $this->output->writeln('');
            $this->output->writeln('Did you mean one of these?');
            foreach (\array_slice($suggestions, 0, 3) as $suggestion) {
                $this->output->writeln(\sprintf('  • %s', Style::value($suggestion['id'])));
            }
        } else {
            $this->output->writeln('');
            $this->output->writeln('Available prompts:');
            $promptIds = \array_keys($allPrompts);
            \sort($promptIds);
            foreach (\array_slice($promptIds, 0, 5) as $id) {
                $this->output->writeln(\sprintf('  • %s', Style::value($id)));
            }

            if (\count($promptIds) > 5) {
                $this->output->writeln(\sprintf('  ... and %d more', \count($promptIds) - 5));
                $this->output->writeln('');
                $this->output->writeln('Use ' . Style::command('prompts:list') . ' to see all available prompts.');
            }
        }
    }

    /**
     * Formats the prompt type for display.
     */
    private function formatPromptType(PromptType $type): string
    {
        return match ($type) {
            PromptType::Prompt => Style::success('Prompt'),
            PromptType::Template => Style::info('Template'),
        };
    }
}
