<?php

declare(strict_types=1);

namespace App\Framework\Console\Commands;

use App\Framework\Console\CommandGroup;
use App\Framework\Console\CommandList;
use App\Framework\Console\CommandRegistry;
use App\Framework\Console\ConsoleColor;
use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ConsoleInput;
use App\Framework\Console\ConsoleOutputInterface;
use App\Framework\Console\ErrorRecovery\CommandSuggestionEngine;
use App\Framework\Console\ExitCode;

#[CommandGroup(
    name: 'System',
    description: 'System commands for console management and diagnostics',
    icon: '⚙️',
    priority: 90
)]
final class ErrorRecoveryCommand
{
    private ?CommandSuggestionEngine $suggestionEngine = null;

    public function __construct(
        private readonly CommandRegistry $commandRegistry
    ) {
    }

    private function getCommandList(): CommandList
    {
        return $this->commandRegistry->getCommandList();
    }

    private function getSuggestionEngine(): CommandSuggestionEngine
    {
        if ($this->suggestionEngine === null) {
            $this->suggestionEngine = new CommandSuggestionEngine($this->getCommandList());
        }

        return $this->suggestionEngine;
    }

    #[ConsoleCommand('suggest', 'Get command suggestions for a given input')]
    public function suggestCommands(ConsoleInput $input, ConsoleOutputInterface $output): ExitCode
    {
        $command = $input->getArgument(0);

        if ($command === null) {
            $output->writeLine("❌ Please provide a command to get suggestions for.", ConsoleColor::RED);
            $output->newLine();
            $output->writeLine("Usage: suggest <command>", ConsoleColor::YELLOW);
            $output->writeLine("Example: suggest database", ConsoleColor::GRAY);

            return ExitCode::INVALID_INPUT;
        }

        $output->writeLine("🔍 Command Suggestions for: '{$command}'", ConsoleColor::BRIGHT_CYAN);
        $output->newLine();

        $suggestions = $this->getSuggestionEngine()->suggestCommand($command);

        if ($suggestions->hasSuggestions()) {
            $output->writeLine($suggestions->formatForDisplay(), ConsoleColor::WHITE);
        } else {
            $output->writeLine("No similar commands found.", ConsoleColor::YELLOW);
            $this->showAlternativeHelp($output);
        }

        return ExitCode::SUCCESS;
    }

    #[ConsoleCommand('commands:by-category', 'List commands by category')]
    public function listCommandsByCategory(ConsoleInput $input, ConsoleOutputInterface $output): ExitCode
    {
        $category = $input->getArgument(0);

        if ($category) {
            return $this->showSpecificCategory($category, $output);
        }

        $output->writeLine("📋 Commands by Category", ConsoleColor::BRIGHT_CYAN);
        $output->newLine();

        $categories = $this->categorizeCommands();

        foreach ($categories as $categoryName => $commands) {
            $count = count($commands);
            $output->writeLine("📁 {$categoryName} ({$count} commands)", ConsoleColor::BRIGHT_YELLOW);

            foreach (array_slice($commands, 0, 5) as $command) {
                $output->writeLine("  • {$command->name} - {$command->description}", ConsoleColor::WHITE);
            }

            if ($count > 5) {
                $remaining = $count - 5;
                $output->writeLine("  ... and {$remaining} more", ConsoleColor::GRAY);
            }
            $output->newLine();
        }

        $output->writeLine("💡 Use 'commands:by-category <category>' to see all commands in a specific category", ConsoleColor::CYAN);

        return ExitCode::SUCCESS;
    }

    #[ConsoleCommand('commands:search', 'Search commands by keyword')]
    public function searchCommands(ConsoleInput $input, ConsoleOutputInterface $output): ExitCode
    {
        $keyword = $input->getArgument(0);

        if ($keyword === null) {
            $output->writeLine("❌ Please provide a keyword to search for.", ConsoleColor::RED);
            $output->newLine();
            $output->writeLine("Usage: commands:search <keyword>", ConsoleColor::YELLOW);
            $output->writeLine("Example: commands:search database", ConsoleColor::GRAY);

            return ExitCode::INVALID_INPUT;
        }

        $output->writeLine("🔍 Searching commands for: '{$keyword}'", ConsoleColor::BRIGHT_CYAN);
        $output->newLine();

        $matches = $this->searchCommandsByKeyword($keyword);

        if (empty($matches)) {
            $output->writeLine("No commands found matching '{$keyword}'.", ConsoleColor::YELLOW);
            $output->newLine();
            $this->showSearchHelp($output);

            return ExitCode::SUCCESS;
        }

        $output->writeLine("Found " . count($matches) . " matching commands:", ConsoleColor::GREEN);
        $output->newLine();

        foreach ($matches as $match) {
            $output->writeLine("📌 {$match['command']->name}", ConsoleColor::BRIGHT_WHITE);
            $output->writeLine("   {$match['command']->description}", ConsoleColor::WHITE);
            $output->writeLine("   Match reason: {$match['reason']}", ConsoleColor::GRAY);
            $output->newLine();
        }

        return ExitCode::SUCCESS;
    }

    #[ConsoleCommand('commands:similar', 'Find commands similar to a specific command')]
    public function findSimilarCommands(ConsoleInput $input, ConsoleOutputInterface $output): ExitCode
    {
        $commandName = $input->getArgument(0);

        if ($commandName === null) {
            $output->writeLine("❌ Please provide a command name to find similar commands for.", ConsoleColor::RED);
            $output->newLine();
            $output->writeLine("Usage: commands:similar <command>", ConsoleColor::YELLOW);
            $output->writeLine("Example: commands:similar db:migrate", ConsoleColor::GRAY);

            return ExitCode::INVALID_INPUT;
        }

        if (! $this->getCommandList()->has($commandName)) {
            $output->writeLine("❌ Command '{$commandName}' not found.", ConsoleColor::RED);
            $output->newLine();

            // Use suggestion engine for alternatives
            $suggestions = $this->getSuggestionEngine()->suggestCommand($commandName);
            if ($suggestions->hasSuggestions()) {
                $output->writeLine("Did you mean:", ConsoleColor::YELLOW);
                $output->writeLine($suggestions->formatForDisplay(), ConsoleColor::WHITE);
            }

            return ExitCode::COMMAND_NOT_FOUND;
        }

        $baseCommand = $this->getCommandList()->get($commandName);
        $similar = $this->getSuggestionEngine()->suggestSimilarCommands($baseCommand, 10);

        $output->writeLine("🔗 Commands similar to '{$commandName}':", ConsoleColor::BRIGHT_CYAN);
        $output->newLine();

        if (empty($similar)) {
            $output->writeLine("No similar commands found.", ConsoleColor::YELLOW);

            return ExitCode::SUCCESS;
        }

        foreach ($similar as $rel) {
            $percentage = round($rel['similarity'] * 100);
            $output->writeLine("📌 {$rel['command']->name} ({$percentage}% similarity)", ConsoleColor::BRIGHT_WHITE);
            $output->writeLine("   {$rel['command']->description}", ConsoleColor::WHITE);
            $output->writeLine("   Relation: {$rel['relation']->getDisplayText()}", ConsoleColor::GRAY);
            $output->newLine();
        }

        return ExitCode::SUCCESS;
    }

    #[ConsoleCommand('help:interactive', 'Interactive help system')]
    public function interactiveHelp(ConsoleInput $input, ConsoleOutputInterface $output): ExitCode
    {
        $output->writeLine("🤝 Interactive Help System", ConsoleColor::BRIGHT_CYAN);
        $output->newLine();

        $output->writeLine("What would you like to do?", ConsoleColor::BRIGHT_YELLOW);
        $output->writeLine("1. Find a command for a specific task", ConsoleColor::WHITE);
        $output->writeLine("2. Explore commands by category", ConsoleColor::WHITE);
        $output->writeLine("3. Search commands by keyword", ConsoleColor::WHITE);
        $output->writeLine("4. Get help with a specific command", ConsoleColor::WHITE);
        $output->writeLine("5. See all available commands", ConsoleColor::WHITE);
        $output->newLine();

        $output->writeLine("Examples:", ConsoleColor::CYAN);
        $output->writeLine("  php console.php suggest database", ConsoleColor::GRAY);
        $output->writeLine("  php console.php commands:by-category db", ConsoleColor::GRAY);
        $output->writeLine("  php console.php commands:search migration", ConsoleColor::GRAY);
        $output->writeLine("  php console.php help db:migrate", ConsoleColor::GRAY);
        $output->writeLine("  php console.php help", ConsoleColor::GRAY);

        return ExitCode::SUCCESS;
    }

    private function showSpecificCategory(string $category, ConsoleOutputInterface $output): ExitCode
    {
        $categories = $this->categorizeCommands();

        if (! isset($categories[$category])) {
            $output->writeLine("❌ Category '{$category}' not found.", ConsoleColor::RED);
            $output->newLine();

            $availableCategories = array_keys($categories);
            $output->writeLine("Available categories:", ConsoleColor::YELLOW);
            foreach ($availableCategories as $cat) {
                $output->writeLine("  • {$cat}", ConsoleColor::WHITE);
            }

            return ExitCode::COMMAND_NOT_FOUND;
        }

        $commands = $categories[$category];
        $output->writeLine("📁 Commands in category '{$category}' (" . count($commands) . " commands)", ConsoleColor::BRIGHT_CYAN);
        $output->newLine();

        foreach ($commands as $command) {
            $output->writeLine("📌 {$command->name}", ConsoleColor::BRIGHT_WHITE);
            $output->writeLine("   {$command->description}", ConsoleColor::WHITE);
            $output->newLine();
        }

        return ExitCode::SUCCESS;
    }

    private function categorizeCommands(): array
    {
        $categories = [];

        foreach ($this->getCommandList()->getAllCommands() as $command) {
            $parts = explode(':', $command->name);
            $category = $parts[0];

            if (! isset($categories[$category])) {
                $categories[$category] = [];
            }

            $categories[$category][] = $command;
        }

        ksort($categories);

        return $categories;
    }

    private function searchCommandsByKeyword(string $keyword): array
    {
        $matches = [];
        $keyword = strtolower($keyword);

        foreach ($this->getCommandList()->getAllCommands() as $command) {
            $reasons = [];

            // Check command name
            if (str_contains(strtolower($command->name), $keyword)) {
                $reasons[] = 'command name';
            }

            // Check description
            if (str_contains(strtolower($command->description), $keyword)) {
                $reasons[] = 'description';
            }

            // Check individual words
            $commandWords = preg_split('/[:\-_\s]+/', strtolower($command->name));
            $descWords = preg_split('/\s+/', strtolower($command->description));

            if (in_array($keyword, $commandWords, true)) {
                $reasons[] = 'command word';
            }

            if (in_array($keyword, $descWords, true)) {
                $reasons[] = 'description word';
            }

            if (! empty($reasons)) {
                $matches[] = [
                    'command' => $command,
                    'reason' => implode(', ', $reasons),
                ];
            }
        }

        return $matches;
    }

    private function showAlternativeHelp(ConsoleOutputInterface $output): void
    {
        $output->writeLine("💡 Try these alternatives:", ConsoleColor::CYAN);
        $output->writeLine("  • Use 'help' to see all available commands", ConsoleColor::WHITE);
        $output->writeLine("  • Use 'commands:by-category' to browse by category", ConsoleColor::WHITE);
        $output->writeLine("  • Use 'commands:search <keyword>' to search by keyword", ConsoleColor::WHITE);
        $output->writeLine("  • Use 'help:interactive' for guided help", ConsoleColor::WHITE);
    }

    private function showSearchHelp(ConsoleOutputInterface $output): void
    {
        $output->writeLine("💡 Search tips:", ConsoleColor::CYAN);
        $output->writeLine("  • Try simpler keywords (e.g., 'db' instead of 'database')", ConsoleColor::WHITE);
        $output->writeLine("  • Try synonyms or related terms", ConsoleColor::WHITE);
        $output->writeLine("  • Use 'commands:by-category' to browse categories", ConsoleColor::WHITE);
        $output->writeLine("  • Use 'help' to see all commands", ConsoleColor::WHITE);
    }
}
