<?php

declare(strict_types=1);

namespace App\Framework\Console\Commands;

use App\Framework\Console\CommandGroup;
use App\Framework\Console\ConsoleColor;
use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ConsoleInput;
use App\Framework\Console\ConsoleOutputInterface;
use App\Framework\Console\ExitCode;
use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
use App\Framework\Performance\PerformanceCategory;

#[CommandGroup(
    name: 'Performance',
    description: 'Console performance monitoring and analysis commands',
    icon: '📊',
    priority: 80
)]
final readonly class SlowCommandsCommand
{
    public function __construct(
        private PerformanceCollectorInterface $performanceCollector
    ) {
    }

    #[ConsoleCommand('perf:slow-commands', 'Show slowest console commands')]
    public function showSlowCommands(ConsoleInput $input, ConsoleOutputInterface $output, int $limit = 10, float $threshold = 1000.0): ExitCode
    {

        $output->writeLine('🐌 Slowest Console Commands', ConsoleColor::BRIGHT_YELLOW);
        $output->writeLine(sprintf('Threshold: %.0fms | Showing top %d', $threshold, $limit), ConsoleColor::GRAY);
        $output->newLine();

        $consoleMetrics = $this->performanceCollector->getMetrics(PerformanceCategory::CONSOLE);

        $slowCommands = $this->findSlowCommands($consoleMetrics, $threshold);

        if (empty($slowCommands)) {
            $output->writeLine('🎉 No slow commands found!', ConsoleColor::GREEN);
            $output->writeLine(sprintf('All commands executed faster than %.0fms', $threshold), ConsoleColor::GRAY);

            return ExitCode::SUCCESS;
        }

        // Sort by duration (descending)
        usort($slowCommands, fn ($a, $b) => $b['duration'] <=> $a['duration']);

        $slowCommands = array_slice($slowCommands, 0, $limit);

        $this->displaySlowCommandsTable($output, $slowCommands);
        $output->newLine();
        $this->displayPerformanceRecommendations($output, $slowCommands);

        return ExitCode::SUCCESS;
    }

    #[ConsoleCommand('perf:watch-slow', 'Monitor for slow commands in real-time')]
    public function watchSlowCommands(ConsoleInput $input, ConsoleOutputInterface $output, float $threshold = 5000.0): ExitCode
    {

        $output->writeLine('👀 Monitoring Slow Commands', ConsoleColor::BRIGHT_CYAN);
        $output->writeLine(sprintf('Threshold: %.0fms | Press Ctrl+C to stop', $threshold), ConsoleColor::GRAY);
        $output->newLine();

        $lastMetricsCount = 0;

        while (true) {
            $consoleMetrics = $this->performanceCollector->getMetrics(PerformanceCategory::CONSOLE);
            $currentMetricsCount = count($consoleMetrics);

            // Check if new metrics were added
            if ($currentMetricsCount > $lastMetricsCount) {
                $newMetrics = array_slice($consoleMetrics, $lastMetricsCount);
                $this->checkForSlowCommands($output, $newMetrics, $threshold);
                $lastMetricsCount = $currentMetricsCount;
            }

            usleep(500000); // Wait 0.5 seconds
        }
    }

    #[ConsoleCommand('perf:profile-command', 'Profile a specific command execution')]
    public function profileCommand(ConsoleInput $input, ConsoleOutputInterface $output, string $commandName, string ...$args): ExitCode
    {

        $output->writeLine("🔍 Profiling Command: {$commandName}", ConsoleColor::BRIGHT_BLUE);
        $output->newLine();

        // Get baseline metrics
        $beforeMetrics = $this->getCommandMetrics($commandName);

        $output->writeLine('📊 Baseline metrics captured', ConsoleColor::GRAY);
        $output->writeLine("Execute the command now: php console.php {$commandName} " . implode(' ', $args), ConsoleColor::YELLOW);
        $output->writeLine('Press Enter when command execution is complete...', ConsoleColor::GRAY);

        // Wait for user input
        fgets(STDIN);

        // Get after metrics
        $afterMetrics = $this->getCommandMetrics($commandName);

        $this->displayProfilingResults($output, $commandName, $beforeMetrics, $afterMetrics);

        return ExitCode::SUCCESS;
    }

    private function findSlowCommands(array $metrics, float $threshold): array
    {
        $slowCommands = [];

        foreach ($metrics as $metric) {
            $key = $metric->getKey();

            // Look for command timing metrics
            if (str_contains($key, 'console_command_') && ! str_contains($key, '_error') && ! str_contains($key, '_memory')) {
                $duration = $metric->getTotalDuration();

                if ($duration >= $threshold) {
                    $context = $metric->getContext();
                    $commandName = $context['command_name'] ?? $this->extractCommandNameFromKey($key);

                    $slowCommands[] = [
                        'command' => $commandName,
                        'duration' => $duration,
                        'executions' => $metric->getCount(),
                        'average_duration' => $metric->getAverageDuration(),
                        'memory_usage' => $this->getMemoryUsageForCommand($metrics, $commandName),
                    ];
                }
            }
        }

        return $slowCommands;
    }

    private function displaySlowCommandsTable(ConsoleOutputInterface $output, array $slowCommands): void
    {
        $output->writeLine('┌─────────────────────────────────────────────────────────────────────┐', ConsoleColor::GRAY);
        $output->writeLine('│ Command                    │ Duration │ Executions │ Avg    │ Memory │', ConsoleColor::GRAY);
        $output->writeLine('├─────────────────────────────────────────────────────────────────────┤', ConsoleColor::GRAY);

        foreach ($slowCommands as $command) {
            $commandName = str_pad(substr($command['command'], 0, 25), 26);
            $duration = str_pad(sprintf('%.0fms', $command['duration']), 8);
            $executions = str_pad((string) $command['executions'], 10);
            $average = str_pad(sprintf('%.0fms', $command['average_duration']), 6);
            $memory = str_pad(sprintf('%.1fMB', $command['memory_usage']), 6);

            $color = $command['duration'] > 10000 ? ConsoleColor::RED :
                ($command['duration'] > 5000 ? ConsoleColor::YELLOW : ConsoleColor::WHITE);

            $output->writeLine("│ {$commandName} │ {$duration} │ {$executions} │ {$average} │ {$memory} │", $color);
        }

        $output->writeLine('└─────────────────────────────────────────────────────────────────────┘', ConsoleColor::GRAY);
    }

    private function displayPerformanceRecommendations(ConsoleOutputInterface $output, array $slowCommands): void
    {
        $output->writeLine('💡 Performance Recommendations', ConsoleColor::BRIGHT_WHITE);
        $output->writeLine('─────────────────────────────', ConsoleColor::GRAY);

        $recommendations = [];

        foreach ($slowCommands as $command) {
            if ($command['duration'] > 30000) {
                $recommendations[] = "🔴 {$command['command']}: Consider breaking into smaller operations or adding progress indicators";
            } elseif ($command['duration'] > 10000) {
                $recommendations[] = "🟡 {$command['command']}: Investigate for optimization opportunities";
            }

            if ($command['memory_usage'] > 100) {
                $recommendations[] = "💾 {$command['command']}: High memory usage - consider streaming or batch processing";
            }
        }

        if (empty($recommendations)) {
            $output->writeLine('All commands are performing within acceptable limits! ✅', ConsoleColor::GREEN);
        } else {
            foreach ($recommendations as $recommendation) {
                $output->writeLine("  {$recommendation}", ConsoleColor::WHITE);
            }
        }
    }

    private function checkForSlowCommands(ConsoleOutputInterface $output, array $newMetrics, float $threshold): void
    {
        foreach ($newMetrics as $metric) {
            $duration = $metric->getTotalDuration();

            if ($duration >= $threshold) {
                $context = $metric->getContext();
                $commandName = $context['command_name'] ?? 'unknown';
                $timestamp = date('H:i:s');

                $output->writeLine(
                    sprintf('[%s] 🐌 Slow command detected: %s (%.0fms)', $timestamp, $commandName, $duration),
                    ConsoleColor::RED
                );
            }
        }
    }

    private function getCommandMetrics(string $commandName): array
    {
        $allMetrics = $this->performanceCollector->getMetrics(PerformanceCategory::CONSOLE);

        return array_filter($allMetrics, function ($metric) use ($commandName) {
            return str_contains($metric->getKey(), $commandName);
        });
    }

    private function displayProfilingResults(ConsoleOutputInterface $output, string $commandName, array $before, array $after): void
    {
        $output->writeLine("📈 Profiling Results for: {$commandName}", ConsoleColor::BRIGHT_GREEN);
        $output->writeLine('───────────────────────────────────────', ConsoleColor::GRAY);

        $newMetrics = array_diff_key($after, $before);

        if (empty($newMetrics)) {
            $output->writeLine('No new metrics detected for this command execution.', ConsoleColor::YELLOW);

            return;
        }

        foreach ($newMetrics as $metric) {
            $output->writeLine(sprintf('  %s: %s', $metric->getKey(), $metric->getFormattedValue()), ConsoleColor::WHITE);
        }
    }

    private function extractCommandNameFromKey(string $key): string
    {
        if (preg_match('/console_command_(.+)/', $key, $matches)) {
            return $matches[1];
        }

        return 'unknown';
    }

    private function getMemoryUsageForCommand(array $metrics, string $commandName): float
    {
        foreach ($metrics as $metric) {
            if (str_contains($metric->getKey(), "console_memory_usage") &&
                str_contains($metric->getKey(), $commandName)) {
                return $metric->getValue();
            }
        }

        return 0.0;
    }
}
