<?php

declare(strict_types=1);

namespace App\Framework\Cache\Warming\Commands;

use App\Framework\Attributes\ConsoleCommand;
use App\Framework\Cache\Warming\CacheWarmingService;
use App\Framework\Cache\Warming\ValueObjects\WarmupPriority;
use App\Framework\Console\ExitCode;
use App\Framework\Console\Input\ConsoleInput;

/**
 * Console command for cache warmup operations
 *
 * Usage:
 *   php console.php cache:warmup                    # Warm all strategies
 *   php console.php cache:warmup --strategy=critical_path  # Warm specific strategy
 *   php console.php cache:warmup --priority=high    # Warm by priority level
 *   php console.php cache:warmup --list             # List available strategies
 */
#[ConsoleCommand(
    name: 'cache:warmup',
    description: 'Warm up cache using registered warming strategies'
)]
final readonly class CacheWarmupCommand
{
    public function __construct(
        private CacheWarmingService $warmingService
    ) {}

    public function execute(ConsoleInput $input): int
    {
        // List strategies
        if ($input->getOption('list', false)) {
            return $this->listStrategies();
        }

        // Specific strategy
        if ($strategyName = $input->getOption('strategy')) {
            return $this->warmStrategy($strategyName);
        }

        // Priority-based warming
        if ($priorityLevel = $input->getOption('priority')) {
            return $this->warmByPriority($priorityLevel);
        }

        // Warm all
        return $this->warmAll($input->getOption('force', false));
    }

    private function warmAll(bool $force): int
    {
        echo "🔥 Warming all cache strategies...\n\n";

        if ($force) {
            echo "⚠️  Force mode: Ignoring shouldRun() checks\n\n";
        }

        $estimatedDuration = $this->warmingService->getEstimatedTotalDuration();
        echo "⏱️  Estimated duration: {$estimatedDuration} seconds\n\n";

        $metrics = $this->warmingService->warmAll($force);

        $this->displayMetrics($metrics);

        return $metrics->totalItemsFailed > 0 ? ExitCode::ERROR : ExitCode::SUCCESS;
    }

    private function warmStrategy(string $strategyName): int
    {
        echo "🔥 Warming strategy: {$strategyName}\n\n";

        try {
            $result = $this->warmingService->warmStrategy($strategyName);

            echo "Strategy: {$result->strategyName}\n";
            echo "Items warmed: {$result->itemsWarmed}\n";
            echo "Items failed: {$result->itemsFailed}\n";
            echo "Duration: " . round($result->durationSeconds, 3) . "s\n";
            echo "Memory used: " . round($result->getMemoryUsedMB(), 2) . " MB\n";
            echo "Success rate: " . round($result->getSuccessRate() * 100, 2) . "%\n";

            if (!empty($result->errors)) {
                echo "\n⚠️  Errors:\n";
                foreach ($result->errors as $error) {
                    echo "  - " . ($error['item'] ?? 'unknown') . ": " . $error['error'] . "\n";
                }
            }

            return $result->isSuccess() ? ExitCode::SUCCESS : ExitCode::ERROR;
        } catch (\InvalidArgumentException $e) {
            echo "❌ Error: {$e->getMessage()}\n\n";
            echo "Use --list to see available strategies.\n";
            return ExitCode::ERROR;
        }
    }

    private function warmByPriority(string $priorityLevel): int
    {
        $priority = $this->parsePriority($priorityLevel);

        if ($priority === null) {
            echo "❌ Invalid priority level: {$priorityLevel}\n";
            echo "Valid values: critical, high, medium, low, background\n";
            return ExitCode::ERROR;
        }

        echo "🔥 Warming strategies with priority >= {$priorityLevel} ({$priority})\n\n";

        $metrics = $this->warmingService->warmByPriority($priority);

        $this->displayMetrics($metrics);

        return $metrics->totalItemsFailed > 0 ? ExitCode::ERROR : ExitCode::SUCCESS;
    }

    private function listStrategies(): int
    {
        echo "📋 Available Cache Warming Strategies:\n\n";

        $strategies = $this->warmingService->getStrategies();

        if (empty($strategies)) {
            echo "No strategies registered.\n";
            return ExitCode::SUCCESS;
        }

        foreach ($strategies as $strategy) {
            $shouldRun = $strategy['should_run'] ? '✅' : '⏸️';
            echo "{$shouldRun} {$strategy['name']}\n";
            echo "   Priority: {$strategy['priority']}\n";
            echo "   Estimated duration: {$strategy['estimated_duration']}s\n";
            echo "   Should run: " . ($strategy['should_run'] ? 'yes' : 'no') . "\n\n";
        }

        $totalDuration = $this->warmingService->getEstimatedTotalDuration();
        echo "⏱️  Total estimated duration: {$totalDuration} seconds\n";

        return ExitCode::SUCCESS;
    }

    private function displayMetrics($metrics): void
    {
        echo "\n📊 Warmup Results:\n";
        echo "==================\n";
        echo "Strategies executed: {$metrics->totalStrategiesExecuted}\n";
        echo "Items warmed: {$metrics->totalItemsWarmed}\n";
        echo "Items failed: {$metrics->totalItemsFailed}\n";
        echo "Duration: " . round($metrics->totalDurationSeconds, 3) . "s\n";
        echo "Memory used: " . round($metrics->getTotalMemoryUsedMB(), 2) . " MB\n";
        echo "Success rate: " . round($metrics->getOverallSuccessRate() * 100, 2) . "%\n";
        echo "Items/second: " . round($metrics->getAverageItemsPerSecond(), 2) . "\n\n";

        if ($metrics->totalStrategiesExecuted > 0) {
            echo "📋 Strategy Details:\n";
            foreach ($metrics->strategyResults as $result) {
                $icon = $result['is_success'] ? '✅' : '❌';
                echo "{$icon} {$result['strategy_name']}: {$result['items_warmed']} items, " .
                     "{$result['duration_seconds']}s\n";
            }
        }
    }

    private function parsePriority(string $level): ?int
    {
        return match (strtolower($level)) {
            'critical' => WarmupPriority::CRITICAL->value,
            'high' => WarmupPriority::HIGH->value,
            'medium' => WarmupPriority::MEDIUM->value,
            'low' => WarmupPriority::LOW->value,
            'background' => WarmupPriority::BACKGROUND->value,
            default => null
        };
    }
}
