<?php

declare(strict_types=1);

namespace App\Framework\Console\Health\Commands;

use App\Framework\Console\Attributes\ConsoleCommand;
use App\Framework\Console\ExitCode;
use App\Framework\Console\Health\HealthService;
use App\Framework\Console\Health\HealthStatus;
use App\Framework\Console\Input\ConsoleInput;
use App\Framework\Console\Layout\ResponsiveOutput;
use App\Framework\Console\Output\ConsoleOutput;

final readonly class HealthCheckCommand
{
    public function __construct(
        private HealthService $healthService
    ) {
    }

    #[ConsoleCommand(
        name: 'health:check',
        description: 'Run console system health checks'
    )]
    public function checkHealth(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $checkName = $input->getArgument('check');
        $requiredOnly = $input->hasOption('required');
        $verbose = $input->hasOption('verbose');
        $json = $input->hasOption('json');

        if ($checkName) {
            return $this->runSingleCheck($checkName, $output, $verbose, $json);
        }

        if ($requiredOnly) {
            return $this->runRequiredChecks($output, $verbose, $json);
        }

        return $this->runAllChecks($output, $verbose, $json);
    }

    #[ConsoleCommand(
        name: 'health:list',
        description: 'List available health checks'
    )]
    public function listChecks(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $checks = $this->healthService->getAvailableChecks();
        $responsiveOutput = ResponsiveOutput::create($output);

        $output->writeLine("<yellow>Available Health Checks:</yellow>\n");

        // Prepare table data
        $headers = ['Name', 'Required', 'Description'];
        $rows = [];

        foreach ($checks as $check) {
            $rows[] = [
                $check['name'],
                $check['required'] ? 'Yes' : 'No',
                $check['description'],
            ];
        }

        $responsiveOutput->writeTable($headers, $rows);

        $output->writeLine('');
        $responsiveOutput->writeList([
            'health:check' => 'Run all checks',
            'health:check --required' => 'Run only required checks',
            'health:check "Check Name"' => 'Run specific check',
            'health:check --json' => 'Output as JSON',
        ], 'Usage:');

        return ExitCode::SUCCESS;
    }

    private function runSingleCheck(string $checkName, ConsoleOutput $output, bool $verbose, bool $json): ExitCode
    {
        $result = $this->healthService->runCheck($checkName);

        if ($result === null) {
            $output->writeLine("<red>Health check '{$checkName}' not found.</red>");

            return ExitCode::NOT_FOUND;
        }

        if ($json) {
            $output->writeLine(json_encode($result->toArray(), JSON_PRETTY_PRINT));

            return ExitCode::SUCCESS;
        }

        $this->displaySingleResult($checkName, $result, $output, $verbose);

        return $result->isUnhealthy() ? ExitCode::GENERAL_ERROR : ExitCode::SUCCESS;
    }

    private function runRequiredChecks(ConsoleOutput $output, bool $verbose, bool $json): ExitCode
    {
        $report = $this->healthService->runRequiredChecks();

        if ($json) {
            $output->writeLine(json_encode($report->toArray(), JSON_PRETTY_PRINT));

            return ExitCode::SUCCESS;
        }

        $this->displayReport($report, $output, $verbose, 'Required Health Checks');

        return $report->isUnhealthy() ? ExitCode::GENERAL_ERROR : ExitCode::SUCCESS;
    }

    private function runAllChecks(ConsoleOutput $output, bool $verbose, bool $json): ExitCode
    {
        $report = $this->healthService->runAllChecks();

        if ($json) {
            $output->writeLine(json_encode($report->toArray(), JSON_PRETTY_PRINT));

            return ExitCode::SUCCESS;
        }

        $this->displayReport($report, $output, $verbose, 'Console System Health Check');

        return $report->isUnhealthy() ? ExitCode::GENERAL_ERROR : ExitCode::SUCCESS;
    }

    private function displayReport($report, ConsoleOutput $output, bool $verbose, string $title): void
    {
        $statusColor = $report->overallStatus->getColor();
        $statusSymbol = $report->overallStatus->getSymbol();

        $output->writeLine("<{$statusColor}>{$title}</>");
        $output->writeLine("<{$statusColor}>{$statusSymbol} Overall Status: {$report->overallStatus->value}</>");
        $output->writeLine('');

        $output->writeLine("Summary:");
        $output->writeLine("  Total Checks: {$report->getCheckCount()}");
        $output->writeLine("  <green>Healthy: {$report->getHealthyCount()}</green>");
        $output->writeLine("  <yellow>Warnings: {$report->getWarningCount()}</yellow>");
        $output->writeLine("  <red>Unhealthy: {$report->getUnhealthyCount()}</red>");
        $output->writeLine('');

        // Show unhealthy checks first
        $unhealthyChecks = $report->getUnhealthyChecks();
        if (! empty($unhealthyChecks)) {
            $output->writeLine('<red>Failed Checks:</red>');
            foreach ($unhealthyChecks as $name => $result) {
                $this->displaySingleResult($name, $result, $output, $verbose);
            }
            $output->writeLine('');
        }

        // Show warning checks
        $warningChecks = $report->getWarningChecks();
        if (! empty($warningChecks)) {
            $output->writeLine('<yellow>Warning Checks:</yellow>');
            foreach ($warningChecks as $name => $result) {
                $this->displaySingleResult($name, $result, $output, $verbose);
            }
            $output->writeLine('');
        }

        // Show healthy checks only in verbose mode
        if ($verbose) {
            $healthyChecks = $report->getHealthyChecks();
            if (! empty($healthyChecks)) {
                $output->writeLine('<green>Healthy Checks:</green>');
                foreach ($healthyChecks as $name => $result) {
                    $this->displaySingleResult($name, $result, $output, $verbose);
                }
            }
        }
    }

    private function displaySingleResult(string $name, $result, ConsoleOutput $output, bool $verbose): void
    {
        $color = $result->status->getColor();
        $symbol = $result->status->getSymbol();

        $output->writeLine("<{$color}>{$symbol} {$name}: {$result->message}</>");

        if ($verbose && ! empty($result->details)) {
            foreach ($result->details as $key => $value) {
                $displayValue = is_array($value) ? implode(', ', $value) : $value;
                $output->writeLine("    {$key}: {$displayValue}");
            }
        }

        if ($result->recommendation) {
            $output->writeLine("    💡 Recommendation: {$result->recommendation}");
        }

        if ($verbose || $result->status !== HealthStatus::HEALTHY) {
            $output->writeLine('');
        }
    }
}
