<?php

declare(strict_types=1);

namespace App\Framework\Queue\Commands;

use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ExitCode;
use App\Framework\Queue\Services\JobMetricsManagerInterface;

final readonly class JobMetricsCommands
{
    public function __construct(
        private JobMetricsManagerInterface $metricsManager
    ) {
    }

    #[ConsoleCommand(name: 'queue:metrics:overview', description: 'Show system-wide queue metrics overview')]
    public function systemOverview(): ExitCode
    {
        try {
            $overview = $this->metricsManager->getSystemOverview();

            echo "🎯 Queue System Overview\n\n";

            // System Health
            $healthIcon = $overview['system_health_score'] >= 70 ? '✅' : '⚠️';
            echo "📊 System Health: {$healthIcon} {$overview['system_health_score']}%\n";
            echo "   Total Queues: {$overview['total_queues']}\n";
            echo "   Healthy Queues: {$overview['healthy_queues']}\n\n";

            // Job Statistics
            echo "📈 Job Statistics (24h):\n";
            echo "   Total Jobs: {$overview['total_jobs']}\n";
            echo "   ✅ Completed: {$overview['completed_jobs']}\n";
            echo "   ❌ Failed: {$overview['failed_jobs']}\n";
            echo "   ⏳ Pending: {$overview['pending_jobs']}\n";
            echo "   🔄 Running: {$overview['running_jobs']}\n";
            echo "   Success Rate: {$overview['overall_success_rate']}%\n\n";

            // Performance
            echo "⚡ Performance:\n";
            echo "   Avg Execution Time: {$overview['average_execution_time_ms']}ms\n";
            echo "   Avg Memory Usage: " . round($overview['average_memory_usage_mb'], 2) . "MB\n\n";

            // Queue Details
            echo "🔗 Queue Details:\n";
            foreach ($overview['queue_metrics'] as $queueName => $metrics) {
                $healthIcon = $metrics->isHealthy() ? '✅' : '⚠️';
                $bottlenecks = $metrics->getBottleneckIndicators();
                $bottleneckText = ! empty($bottlenecks) ? ' (' . implode(', ', $bottlenecks) . ')' : '';

                echo "   {$healthIcon} {$queueName}: {$metrics->totalJobs} jobs, {$metrics->successRate->getValue()}% success{$bottleneckText}\n";
            }

            return ExitCode::SUCCESS;
        } catch (\Exception $e) {
            echo "❌ Error: {$e->getMessage()}\n";

            return ExitCode::GENERAL_ERROR;
        }
    }

    #[ConsoleCommand(name: 'queue:metrics:queue', description: 'Show detailed metrics for a specific queue')]
    public function queueMetrics(string $queueName, string $timeWindow = '1 hour'): ExitCode
    {
        try {
            $metrics = $this->metricsManager->getQueueMetrics($queueName, $timeWindow);

            echo "📊 Queue Metrics: {$queueName} (last {$timeWindow})\n\n";

            // Health Status
            $healthIcon = $metrics->isHealthy() ? '✅' : '⚠️';
            echo "🏥 Health: {$healthIcon} {$metrics->getHealthScore()->getValue()}%\n\n";

            // Job Counts
            echo "📈 Job Statistics:\n";
            echo "   Total: {$metrics->totalJobs}\n";
            echo "   ✅ Completed: {$metrics->completedJobs}\n";
            echo "   ❌ Failed: {$metrics->failedJobs}\n";
            echo "   ⏳ Pending: {$metrics->pendingJobs}\n";
            echo "   🔄 Running: {$metrics->runningJobs}\n";
            echo "   💀 Dead Letter: {$metrics->deadLetterJobs}\n\n";

            // Success/Failure Rates
            echo "📊 Success Metrics:\n";
            echo "   Success Rate: {$metrics->successRate->getValue()}%\n";
            echo "   Failure Rate: {$metrics->getFailureRate()->getValue()}%\n\n";

            // Performance
            echo "⚡ Performance:\n";
            echo "   Avg Execution Time: {$metrics->averageExecutionTimeMs}ms\n";
            echo "   Avg Memory Usage: " . round($metrics->averageMemoryUsageMB, 2) . "MB\n";
            echo "   Throughput: " . round($metrics->throughputJobsPerHour, 2) . " jobs/hour\n\n";

            // Bottlenecks
            $bottlenecks = $metrics->getBottleneckIndicators();
            if (! empty($bottlenecks)) {
                echo "⚠️ Bottleneck Indicators:\n";
                foreach ($bottlenecks as $bottleneck) {
                    echo "   - " . str_replace('_', ' ', ucfirst($bottleneck)) . "\n";
                }
                echo "\n";
            }

            echo "📅 Measured at: {$metrics->measuredAt}\n";

            return ExitCode::SUCCESS;
        } catch (\Exception $e) {
            echo "❌ Error: {$e->getMessage()}\n";

            return ExitCode::GENERAL_ERROR;
        }
    }

    #[ConsoleCommand(name: 'queue:metrics:job', description: 'Show metrics for a specific job')]
    public function jobMetrics(string $jobId): ExitCode
    {
        try {
            $metrics = $this->metricsManager->getJobMetrics($jobId);

            if (! $metrics) {
                echo "❌ No metrics found for job: {$jobId}\n";

                return ExitCode::GENERAL_ERROR;
            }

            echo "📊 Job Metrics: {$jobId}\n\n";

            // Basic Info
            echo "ℹ️ Basic Information:\n";
            echo "   Queue: {$metrics->queueName}\n";
            echo "   Status: {$this->getStatusIcon($metrics->status)} {$metrics->status}\n";
            echo "   Attempts: {$metrics->attempts}/{$metrics->maxAttempts}\n\n";

            // Performance
            echo "⚡ Performance:\n";
            echo "   Execution Time: {$metrics->executionTimeMs}ms (" . round($metrics->getExecutionTimeSeconds(), 2) . "s)\n";
            echo "   Memory Usage: {$metrics->memoryUsageBytes} bytes (" . round($metrics->getMemoryUsageMB(), 2) . "MB)\n";
            echo "   Success Rate: {$metrics->getSuccessRate()->getValue()}%\n\n";

            // Timestamps
            echo "📅 Timeline:\n";
            echo "   Created: {$metrics->createdAt}\n";
            if ($metrics->startedAt) {
                echo "   Started: {$metrics->startedAt}\n";
            }
            if ($metrics->completedAt) {
                echo "   Completed: {$metrics->completedAt}\n";
            }
            if ($metrics->failedAt) {
                echo "   Failed: {$metrics->failedAt}\n";
            }

            $duration = $metrics->getDuration();
            if ($duration !== null) {
                echo "   Duration: {$duration} seconds\n";
            }

            // Error Information
            if ($metrics->errorMessage) {
                echo "\n❌ Error:\n";
                echo "   {$metrics->errorMessage}\n";
            }

            // Metadata
            if (! empty($metrics->metadata)) {
                echo "\n📝 Metadata:\n";
                foreach ($metrics->metadata as $key => $value) {
                    echo "   {$key}: " . json_encode($value) . "\n";
                }
            }

            return ExitCode::SUCCESS;
        } catch (\Exception $e) {
            echo "❌ Error: {$e->getMessage()}\n";

            return ExitCode::GENERAL_ERROR;
        }
    }

    #[ConsoleCommand(name: 'queue:metrics:slow', description: 'Show slowest jobs')]
    public function slowJobs(?string $queueName = null, int $limit = 10): ExitCode
    {
        try {
            $slowJobs = $this->metricsManager->getTopSlowJobs($queueName, $limit);

            $title = $queueName ? "Slowest Jobs in '{$queueName}'" : "Slowest Jobs (All Queues)";
            echo "🐌 {$title} (Top {$limit})\n\n";

            if (empty($slowJobs)) {
                echo "   No jobs found\n";

                return ExitCode::SUCCESS;
            }

            foreach ($slowJobs as $index => $metrics) {
                $rank = $index + 1;
                $statusIcon = $this->getStatusIcon($metrics->status);
                $executionSeconds = round($metrics->getExecutionTimeSeconds(), 2);

                echo "   {$rank}. {$statusIcon} {$metrics->jobId} ({$metrics->queueName})\n";
                echo "      Time: {$metrics->executionTimeMs}ms ({$executionSeconds}s)\n";
                echo "      Memory: " . round($metrics->getMemoryUsageMB(), 2) . "MB\n";
                echo "      Status: {$metrics->status}\n\n";
            }

            return ExitCode::SUCCESS;
        } catch (\Exception $e) {
            echo "❌ Error: {$e->getMessage()}\n";

            return ExitCode::GENERAL_ERROR;
        }
    }

    #[ConsoleCommand(name: 'queue:metrics:memory', description: 'Show jobs with highest memory usage')]
    public function memoryConsumers(?string $queueName = null, int $limit = 10): ExitCode
    {
        try {
            $memoryJobs = $this->metricsManager->getTopMemoryConsumers($queueName, $limit);

            $title = $queueName ? "Top Memory Consumers in '{$queueName}'" : "Top Memory Consumers (All Queues)";
            echo "🧠 {$title} (Top {$limit})\n\n";

            if (empty($memoryJobs)) {
                echo "   No jobs found\n";

                return ExitCode::SUCCESS;
            }

            foreach ($memoryJobs as $index => $metrics) {
                $rank = $index + 1;
                $statusIcon = $this->getStatusIcon($metrics->status);
                $memoryMB = round($metrics->getMemoryUsageMB(), 2);

                echo "   {$rank}. {$statusIcon} {$metrics->jobId} ({$metrics->queueName})\n";
                echo "      Memory: {$metrics->memoryUsageBytes} bytes ({$memoryMB}MB)\n";
                echo "      Time: {$metrics->executionTimeMs}ms\n";
                echo "      Status: {$metrics->status}\n\n";
            }

            return ExitCode::SUCCESS;
        } catch (\Exception $e) {
            echo "❌ Error: {$e->getMessage()}\n";

            return ExitCode::GENERAL_ERROR;
        }
    }

    #[ConsoleCommand(name: 'queue:metrics:failed', description: 'Show recent failed jobs')]
    public function failedJobs(?string $queueName = null, string $timeWindow = '24 hours'): ExitCode
    {
        try {
            $failedJobs = $this->metricsManager->getFailedJobs($queueName, $timeWindow);

            $title = $queueName ? "Failed Jobs in '{$queueName}'" : "Failed Jobs (All Queues)";
            echo "❌ {$title} (last {$timeWindow})\n\n";

            if (empty($failedJobs)) {
                echo "   No failed jobs found\n";

                return ExitCode::SUCCESS;
            }

            foreach ($failedJobs as $metrics) {
                echo "   🔴 {$metrics->jobId} ({$metrics->queueName})\n";
                echo "      Failed: {$metrics->failedAt}\n";
                echo "      Attempts: {$metrics->attempts}/{$metrics->maxAttempts}\n";
                if ($metrics->errorMessage) {
                    echo "      Error: {$metrics->errorMessage}\n";
                }
                echo "\n";
            }

            return ExitCode::SUCCESS;
        } catch (\Exception $e) {
            echo "❌ Error: {$e->getMessage()}\n";

            return ExitCode::GENERAL_ERROR;
        }
    }

    #[ConsoleCommand(name: 'queue:metrics:performance', description: 'Show performance statistics')]
    public function performanceStats(?string $queueName = null, string $timeWindow = '24 hours'): ExitCode
    {
        try {
            $stats = $this->metricsManager->getPerformanceStats($queueName, $timeWindow);

            $title = $queueName ? "Performance Stats for '{$queueName}'" : "System Performance Stats";
            echo "📈 {$title} (last {$timeWindow})\n\n";

            echo "📊 Job Statistics:\n";
            echo "   Total Jobs: {$stats['total_jobs']}\n";
            echo "   Completed: {$stats['completed_jobs']}\n";
            echo "   Failed: {$stats['failed_jobs']}\n";
            echo "   Success Rate: " . round($stats['success_rate'], 2) . "%\n";
            echo "   Failure Rate: " . round($stats['failure_rate'], 2) . "%\n\n";

            echo "⏱️ Execution Time:\n";
            echo "   Average: " . round($stats['average_execution_time_ms'], 2) . "ms\n";
            echo "   Minimum: " . round($stats['min_execution_time_ms'], 2) . "ms\n";
            echo "   Maximum: " . round($stats['max_execution_time_ms'], 2) . "ms\n\n";

            echo "🧠 Memory Usage:\n";
            echo "   Average: " . round($stats['average_memory_usage_mb'], 2) . "MB\n";
            echo "   Minimum: " . round($stats['min_memory_usage_bytes'] / (1024 * 1024), 2) . "MB\n";
            echo "   Maximum: " . round($stats['max_memory_usage_bytes'] / (1024 * 1024), 2) . "MB\n\n";

            echo "🔄 Retry Statistics:\n";
            echo "   Average Attempts: " . round($stats['average_attempts'], 2) . "\n";

            return ExitCode::SUCCESS;
        } catch (\Exception $e) {
            echo "❌ Error: {$e->getMessage()}\n";

            return ExitCode::GENERAL_ERROR;
        }
    }

    #[ConsoleCommand(name: 'queue:metrics:throughput', description: 'Show throughput statistics')]
    public function throughputStats(?string $queueName = null, string $timeWindow = '24 hours'): ExitCode
    {
        try {
            $stats = $this->metricsManager->getThroughputStats($queueName, $timeWindow);

            $title = $queueName ? "Throughput Stats for '{$queueName}'" : "System Throughput Stats";
            echo "🚀 {$title} (last {$timeWindow})\n\n";

            echo "📊 Overall Throughput:\n";
            echo "   Total Completed: {$stats['total_completed']} jobs\n";
            echo "   Average per Hour: " . round($stats['average_throughput_per_hour'], 2) . " jobs/hour\n\n";

            echo "📈 Hourly Breakdown:\n";
            if (empty($stats['hourly_breakdown'])) {
                echo "   No data available\n";
            } else {
                foreach ($stats['hourly_breakdown'] as $hourData) {
                    $hour = date('H:i', strtotime($hourData['hour']));
                    $jobs = $hourData['jobs_completed'];
                    $bar = str_repeat('█', min(50, $jobs)); // Simple bar chart
                    echo "   {$hour}: {$jobs} jobs {$bar}\n";
                }
            }

            return ExitCode::SUCCESS;
        } catch (\Exception $e) {
            echo "❌ Error: {$e->getMessage()}\n";

            return ExitCode::GENERAL_ERROR;
        }
    }

    #[ConsoleCommand(name: 'queue:metrics:cleanup', description: 'Clean up old metrics data')]
    public function cleanupMetrics(int $olderThanDays = 90): ExitCode
    {
        try {
            $deletedCount = $this->metricsManager->cleanupOldMetrics($olderThanDays);

            echo "🧹 Metrics Cleanup Completed\n";
            echo "   Deleted: {$deletedCount} metrics older than {$olderThanDays} days\n";

            if ($deletedCount > 0) {
                echo "   ✅ Cleanup successful\n";
            } else {
                echo "   ℹ️ No old metrics found to clean up\n";
            }

            return ExitCode::SUCCESS;
        } catch (\Exception $e) {
            echo "❌ Error: {$e->getMessage()}\n";

            return ExitCode::GENERAL_ERROR;
        }
    }

    private function getStatusIcon(string $status): string
    {
        return match($status) {
            'pending' => '⏳',
            'running' => '🔄',
            'completed' => '✅',
            'failed' => '❌',
            'dead_letter' => '💀',
            default => '❓'
        };
    }
}
