<?php

declare(strict_types=1);

namespace App\Framework\Queue\Commands;

use App\Framework\Attributes\ConsoleCommand;
use App\Framework\Console\ConsoleOutput;
use App\Framework\Queue\Entities\JobProgressEntry;
use App\Framework\Queue\Services\ProgressManager;

/**
 * Console commands for managing job progress
 */
final readonly class ProgressCommands
{
    public function __construct(
        private ProgressManager $progressManager
    ) {
    }

    #[ConsoleCommand(name: 'queue:progress:show', description: 'Show current progress for a job')]
    public function showProgress(string $jobId, ConsoleOutput $output): void
    {
        $progress = $this->progressManager->getJobProgress($jobId);

        if (! $progress) {
            $output->writeln("<error>No progress found for job: {$jobId}</error>");

            return;
        }

        $output->writeln("<info>Job Progress for: {$jobId}</info>");
        $output->writeln("Percentage: {$progress->percentage->format()}");
        $output->writeln("Message: {$progress->message}");

        if ($progress->metadata) {
            $output->writeln("Metadata:");
            foreach ($progress->metadata as $key => $value) {
                $valueStr = is_array($value) ? json_encode($value) : (string) $value;
                $output->writeln("  {$key}: {$valueStr}");
            }
        }

        $output->writeln("Status: " . ($progress->isCompleted() ? 'Completed' : ($progress->isFailed() ? 'Failed' : 'In Progress')));
    }

    #[ConsoleCommand(name: 'queue:progress:history', description: 'Show progress history for a job')]
    public function showHistory(string $jobId, ConsoleOutput $output): void
    {
        $history = $this->progressManager->getProgressHistory($jobId);

        if (empty($history)) {
            $output->writeln("<error>No progress history found for job: {$jobId}</error>");

            return;
        }

        $output->writeln("<info>Progress History for: {$jobId}</info>");
        $output->writeln(str_repeat('-', 80));

        foreach ($history as $entry) {
            /** @var JobProgressEntry $entry */
            $output->writeln("Time: {$entry->updatedAt}");
            $output->writeln("Progress: {$entry->getPercentage()->format()}");
            $output->writeln("Message: {$entry->message}");

            if ($entry->stepName) {
                $output->writeln("Step: {$entry->stepName}");
            }

            $status = [];
            if ($entry->isCompleted) {
                $status[] = 'Completed';
            }
            if ($entry->isFailed) {
                $status[] = 'Failed';
            }
            if (! empty($status)) {
                $output->writeln("Status: " . implode(', ', $status));
            }

            $output->writeln(str_repeat('-', 40));
        }
    }

    #[ConsoleCommand(name: 'queue:progress:list', description: 'List recent job progress updates')]
    public function listRecent(ConsoleOutput $output, ?int $minutes = 60, ?int $limit = 20): void
    {
        $recentJobs = $this->progressManager->getRecentlyUpdatedJobs($minutes ?? 60, $limit ?? 20);

        if (empty($recentJobs)) {
            $output->writeln("<info>No recent job progress updates found</info>");

            return;
        }

        $output->writeln("<info>Recent Job Progress Updates (last {$minutes} minutes)</info>");
        $output->writeln(str_repeat('=', 80));

        foreach ($recentJobs as $entry) {
            /** @var JobProgressEntry $entry */
            $output->writeln("Job ID: {$entry->jobId}");
            $output->writeln("Progress: {$entry->getPercentage()->format()}");
            $output->writeln("Message: {$entry->message}");
            $output->writeln("Updated: {$entry->updatedAt}");

            if ($entry->stepName) {
                $output->writeln("Step: {$entry->stepName}");
            }

            $status = [];
            if ($entry->isCompleted) {
                $status[] = 'Completed';
            }
            if ($entry->isFailed) {
                $status[] = 'Failed';
            }
            if (! empty($status)) {
                $output->writeln("Status: " . implode(', ', $status));
            }

            $output->writeln(str_repeat('-', 40));
        }
    }

    #[ConsoleCommand(name: 'queue:progress:above', description: 'List jobs above a certain progress percentage')]
    public function listAboveProgress(float $percentage, ConsoleOutput $output): void
    {
        if ($percentage < 0 || $percentage > 100) {
            $output->writeln("<error>Percentage must be between 0 and 100</error>");

            return;
        }

        $jobs = $this->progressManager->getJobsAboveProgress($percentage);

        if (empty($jobs)) {
            $output->writeln("<info>No jobs found above {$percentage}% progress</info>");

            return;
        }

        $output->writeln("<info>Jobs above {$percentage}% progress</info>");
        $output->writeln(str_repeat('=', 80));

        foreach ($jobs as $entry) {
            /** @var JobProgressEntry $entry */
            $output->writeln("Job ID: {$entry->jobId}");
            $output->writeln("Progress: {$entry->getPercentage()->format()}");
            $output->writeln("Message: {$entry->message}");
            $output->writeln("Updated: {$entry->updatedAt}");

            $status = [];
            if ($entry->isCompleted) {
                $status[] = 'Completed';
            }
            if ($entry->isFailed) {
                $status[] = 'Failed';
            }
            if (! empty($status)) {
                $output->writeln("Status: " . implode(', ', $status));
            }

            $output->writeln(str_repeat('-', 40));
        }
    }

    #[ConsoleCommand(name: 'queue:progress:cleanup', description: 'Clean up old progress entries')]
    public function cleanup(ConsoleOutput $output, ?int $days = 30): void
    {
        $deletedCount = $this->progressManager->cleanupOldProgress($days ?? 30);

        $output->writeln("<info>Cleaned up {$deletedCount} old progress entries older than {$days} days</info>");
    }

    #[ConsoleCommand(name: 'queue:progress:multiple', description: 'Show progress for multiple jobs (comma-separated IDs)')]
    public function showMultiple(string $jobIds, ConsoleOutput $output): void
    {
        $idArray = array_map('trim', explode(',', $jobIds));

        if (empty($idArray)) {
            $output->writeln("<error>No job IDs provided</error>");

            return;
        }

        $progressData = $this->progressManager->getMultipleJobProgress($idArray);

        if (empty($progressData)) {
            $output->writeln("<error>No progress found for any of the provided job IDs</error>");

            return;
        }

        $output->writeln("<info>Progress for multiple jobs</info>");
        $output->writeln(str_repeat('=', 80));

        foreach ($idArray as $jobId) {
            $output->writeln("Job ID: {$jobId}");

            if (isset($progressData[$jobId])) {
                $progress = $progressData[$jobId];
                $output->writeln("  Progress: {$progress->percentage->format()}");
                $output->writeln("  Message: {$progress->message}");
                $output->writeln("  Status: " . ($progress->isCompleted() ? 'Completed' : ($progress->isFailed() ? 'Failed' : 'In Progress')));
            } else {
                $output->writeln("  <comment>No progress data found</comment>");
            }

            $output->writeln(str_repeat('-', 40));
        }
    }
}
