<?php

declare(strict_types=1);

namespace App\Framework\Queue\Commands;

use App\Framework\Attributes\ConsoleCommand as ConsoleCommandAttribute;
use App\Framework\Queue\Contracts\JobBatchManagerInterface;
use App\Framework\Queue\ValueObjects\JobBatchStatus;

/**
 * Console commands for job batch management
 */
final readonly class JobBatchCommands
{
    public function __construct(
        private JobBatchManagerInterface $batchManager
    ) {
    }

    #[ConsoleCommandAttribute(name: 'batch:list', description: 'List job batches')]
    public function listBatches(string $status = 'all', int $limit = 20): void
    {
        if ($status === 'all') {
            // Get batches for all statuses
            $batches = [];
            foreach (JobBatchStatus::cases() as $batchStatus) {
                $statusBatches = $this->batchManager->getBatchesByStatus($batchStatus, $limit);
                $batches = array_merge($batches, $statusBatches);
            }

            // Sort by created_at desc
            usort($batches, fn ($a, $b) => $b->createdAt?->getTimestamp() <=> $a->createdAt?->getTimestamp());
            $batches = array_slice($batches, 0, $limit);
        } else {
            try {
                $batchStatus = JobBatchStatus::from($status);
                $batches = $this->batchManager->getBatchesByStatus($batchStatus, $limit);
            } catch (\ValueError) {
                echo "❌ Invalid status: {$status}. Valid statuses: " .
                     implode(', ', array_map(fn ($s) => $s->value, JobBatchStatus::cases())) . "\n";

                return;
            }
        }

        if (empty($batches)) {
            echo "No batches found" . ($status !== 'all' ? " with status: {$status}" : '') . "\n";

            return;
        }

        echo "📋 Job Batches" . ($status !== 'all' ? " ({$status})" : '') . ":\n\n";

        foreach ($batches as $batch) {
            $icon = $batch->status->getIcon();
            $progress = $batch->getProgressPercentage();
            $remaining = $batch->getRemainingJobs();

            echo "{$icon} {$batch->batchId}\n";
            echo "   Name: {$batch->name}\n";
            echo "   Status: {$batch->status->getDisplayName()}\n";
            echo "   Progress: {$progress}% ({$batch->processedJobs}/{$batch->totalJobs} completed";
            if ($batch->failedJobs > 0) {
                echo ", {$batch->failedJobs} failed";
            }
            if ($remaining > 0) {
                echo ", {$remaining} remaining";
            }
            echo ")\n";
            echo "   Created: {$batch->createdAt?->toRfc3339()}\n";
            if ($batch->startedAt) {
                echo "   Started: {$batch->startedAt->toRfc3339()}\n";
            }
            if ($batch->completedAt) {
                echo "   Completed: {$batch->completedAt->toRfc3339()}\n";
            }
            echo "\n";
        }
    }

    #[ConsoleCommandAttribute(name: 'batch:show', description: 'Show detailed batch information')]
    public function showBatch(string $batchId): void
    {
        $batch = $this->batchManager->getBatch($batchId);

        if (! $batch) {
            echo "❌ Batch not found: {$batchId}\n";

            return;
        }

        $icon = $batch->status->getIcon();
        $progress = $batch->getProgressPercentage();

        echo "{$icon} Batch Details\n";
        echo "================\n\n";
        echo "ID: {$batch->batchId}\n";
        echo "Name: {$batch->name}\n";
        echo "Status: {$batch->status->getDisplayName()}\n";
        echo "Progress: {$progress}%\n\n";

        echo "Job Statistics:\n";
        echo "  Total Jobs: {$batch->totalJobs}\n";
        echo "  Processed: {$batch->processedJobs}\n";
        echo "  Failed: {$batch->failedJobs}\n";
        echo "  Remaining: {$batch->getRemainingJobs()}\n\n";

        echo "Timestamps:\n";
        echo "  Created: {$batch->createdAt?->toRfc3339()}\n";
        if ($batch->startedAt) {
            echo "  Started: {$batch->startedAt->toRfc3339()}\n";
        }
        if ($batch->completedAt) {
            echo "  Completed: {$batch->completedAt->toRfc3339()}\n";
        }
        if ($batch->failedAt) {
            echo "  Failed: {$batch->failedAt->toRfc3339()}\n";
        }
        echo "\n";

        if (! empty($batch->options)) {
            echo "Options:\n";
            foreach ($batch->options as $key => $value) {
                echo "  {$key}: " . (is_array($value) ? json_encode($value) : $value) . "\n";
            }
            echo "\n";
        }

        echo "Job IDs:\n";
        foreach ($batch->jobIds as $index => $jobId) {
            echo "  " . ($index + 1) . ". {$jobId}\n";
        }
    }

    #[ConsoleCommandAttribute(name: 'batch:cancel', description: 'Cancel a job batch')]
    public function cancelBatch(string $batchId): void
    {
        $batch = $this->batchManager->getBatch($batchId);

        if (! $batch) {
            echo "❌ Batch not found: {$batchId}\n";

            return;
        }

        if ($batch->isFinished()) {
            echo "❌ Cannot cancel batch: already finished with status {$batch->status->getDisplayName()}\n";

            return;
        }

        $success = $this->batchManager->cancelBatch($batchId);

        if ($success) {
            echo "✅ Batch cancelled successfully: {$batchId}\n";
        } else {
            echo "❌ Failed to cancel batch: {$batchId}\n";
        }
    }

    #[ConsoleCommandAttribute(name: 'batch:stats', description: 'Show batch statistics')]
    public function showStats(): void
    {
        $stats = $this->batchManager->getBatchStats();

        if (empty($stats)) {
            echo "No batch statistics available\n";

            return;
        }

        echo "📊 Batch Statistics\n";
        echo "==================\n\n";

        $totalBatches = 0;
        $totalJobs = 0;
        $totalFailed = 0;

        foreach ($stats as $status => $data) {
            try {
                $statusEnum = JobBatchStatus::from($status);
                $icon = $statusEnum->getIcon();
                $displayName = $statusEnum->getDisplayName();
            } catch (\ValueError) {
                $icon = '❓';
                $displayName = ucfirst($status);
            }

            echo "{$icon} {$displayName}:\n";
            echo "  Batches: {$data['count']}\n";
            echo "  Total Jobs: {$data['total_jobs']}\n";
            echo "  Failed Jobs: {$data['total_failed']}\n";
            echo "  Avg Processed: " . number_format($data['avg_processed'], 2) . "\n\n";

            $totalBatches += $data['count'];
            $totalJobs += $data['total_jobs'];
            $totalFailed += $data['total_failed'];
        }

        echo "Overall:\n";
        echo "  Total Batches: {$totalBatches}\n";
        echo "  Total Jobs: {$totalJobs}\n";
        echo "  Total Failed: {$totalFailed}\n";
        if ($totalJobs > 0) {
            $failureRate = ($totalFailed / $totalJobs) * 100;
            echo "  Failure Rate: " . number_format($failureRate, 2) . "%\n";
        }
    }

    #[ConsoleCommandAttribute(name: 'batch:cleanup', description: 'Cleanup old finished batches')]
    public function cleanupBatches(int $olderThanDays = 30): void
    {
        if ($olderThanDays < 1) {
            echo "❌ Days must be at least 1\n";

            return;
        }

        echo "🧹 Cleaning up batches older than {$olderThanDays} days...\n";

        $deleted = $this->batchManager->cleanupOldBatches($olderThanDays);

        if ($deleted > 0) {
            echo "✅ Cleaned up {$deleted} old batches\n";
        } else {
            echo "ℹ️ No old batches to clean up\n";
        }
    }

    #[ConsoleCommandAttribute(name: 'batch:progress', description: 'Show batch progress')]
    public function showProgress(string $batchId): void
    {
        $progress = $this->batchManager->getBatchProgress($batchId);

        if (empty($progress)) {
            echo "❌ Batch not found: {$batchId}\n";

            return;
        }

        $statusEnum = JobBatchStatus::from($progress['status']);
        $icon = $statusEnum->getIcon();

        echo "{$icon} {$progress['name']} ({$progress['batch_id']})\n";
        echo "Status: {$statusEnum->getDisplayName()}\n";
        echo "Progress: {$progress['progress_percentage']}%\n";

        // Visual progress bar
        $barWidth = 40;
        $completedWidth = (int) (($progress['progress_percentage'] / 100) * $barWidth);
        $bar = str_repeat('█', $completedWidth) . str_repeat('░', $barWidth - $completedWidth);
        echo "[{$bar}] {$progress['processed_jobs']}/{$progress['total_jobs']}\n";

        if ($progress['failed_jobs'] > 0) {
            echo "❌ Failed: {$progress['failed_jobs']}\n";
        }

        if ($progress['remaining_jobs'] > 0) {
            echo "⏳ Remaining: {$progress['remaining_jobs']}\n";
        }

        if ($progress['is_finished']) {
            echo "✅ Batch completed\n";
        }
    }
}
