<?php

declare(strict_types=1);

namespace App\Framework\Database\Monitoring\Commands;

use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ExitCode;
use App\Framework\Database\DatabaseManager;
use App\Framework\Database\Monitoring\Health\DatabaseHealthChecker;
use App\Framework\Database\Monitoring\Health\HealthCheckStatus;

/**
 * Command to check database health
 */
final readonly class DatabaseHealthCheckCommand
{
    public function __construct(
        private DatabaseHealthChecker $healthChecker,
        private DatabaseManager $databaseManager
    ) {
    }

    /**
     * Check database health
     *
     * @param string $connection The database connection to check
     * @param bool $json Whether to output in JSON format
     * @return ExitCode
     */
    #[ConsoleCommand('db:health', 'Check database health')]
    public function __invoke(string $connection = 'default', bool $json = false): ExitCode
    {
        try {
            // Verify the connection exists
            if (! $this->databaseManager->hasConnection($connection)) {
                $availableConnections = implode(', ', $this->databaseManager->getConnectionNames());
                echo "Error: Connection '{$connection}' not found. Available connections: {$availableConnections}\n";

                return ExitCode::USAGE_ERROR;
            }

            // Run health checks
            $result = $this->healthChecker->checkHealth($connection);

            // Output results
            if ($json) {
                echo json_encode($result->toArray(), JSON_PRETTY_PRINT) . "\n";
            } else {
                $this->displayResults($result);
            }

            // Return exit code based on health status
            return $result->isHealthy() ? ExitCode::SUCCESS : ExitCode::SOFTWARE_ERROR;
        } catch (\Throwable $e) {
            echo "Error: {$e->getMessage()}\n";

            return ExitCode::SOFTWARE_ERROR;
        }
    }

    /**
     * Check health of all database connections
     *
     * @param bool $json Whether to output in JSON format
     * @return ExitCode
     */
    #[ConsoleCommand('db:health:all', 'Check health of all database connections')]
    public function checkAll(bool $json = false): ExitCode
    {
        try {
            $connections = $this->databaseManager->getConnectionNames();
            $results = [];
            $hasErrors = false;

            foreach ($connections as $connection) {
                $result = $this->healthChecker->checkHealth($connection);
                $results[$connection] = $result->toArray();

                if (! $result->isHealthy()) {
                    $hasErrors = true;
                }
            }

            // Output results
            if ($json) {
                echo json_encode($results, JSON_PRETTY_PRINT) . "\n";
            } else {
                foreach ($connections as $connection) {
                    $result = $this->healthChecker->checkHealth($connection);
                    $this->displayResults($result);
                    echo "\n";
                }
            }

            // Return exit code based on health status
            return $hasErrors ? ExitCode::SOFTWARE_ERROR : ExitCode::SUCCESS;
        } catch (\Throwable $e) {
            echo "Error: {$e->getMessage()}\n";

            return ExitCode::SOFTWARE_ERROR;
        }
    }

    /**
     * Display health check results
     */
    private function displayResults($result): void
    {
        $connection = $result->getConnection();
        $timestamp = $result->getTimestamp()->format('Y-m-d H:i:s');
        $overallStatus = $result->getOverallStatus();

        // Display header
        echo "Database Health Check: {$connection}\n";
        echo "Timestamp: {$timestamp}\n";
        echo "Overall Status: " . $this->formatStatus($overallStatus) . "\n";
        echo str_repeat('-', 80) . "\n\n";

        // Display errors
        $errors = $result->getErrors();
        if (! empty($errors)) {
            echo "Errors:\n";
            foreach ($errors as $error) {
                echo "  - {$error['name']}: {$error['message']}\n";
            }
            echo "\n";
        }

        // Display checks
        echo "Health Checks:\n";
        foreach ($result->getChecks() as $check) {
            $status = $check['status'];
            echo "  - {$check['name']}: " . $this->formatStatus($status->status) . "\n";
            echo "    {$status->message}\n";
            if ($status->isWarning() || $status->isError()) {
                echo "    Description: {$check['description']}\n";
            }
            echo "\n";
        }
    }

    /**
     * Format status for display
     */
    private function formatStatus(string $status): string
    {
        return match ($status) {
            HealthCheckStatus::OK => "\033[32mOK\033[0m",
            HealthCheckStatus::WARNING => "\033[33mWARNING\033[0m",
            HealthCheckStatus::ERROR => "\033[31mERROR\033[0m",
            default => $status,
        };
    }
}
