<?php

declare(strict_types=1);

namespace App\Framework\CircuitBreaker\Commands;

use App\Framework\CircuitBreaker\CircuitBreakerManager;
use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ConsoleInput;
use App\Framework\Console\ConsoleOutput;
use App\Framework\Console\ExitCode;

/**
 * Console Command für Circuit Breaker Management
 */
final readonly class CircuitBreakerCommand
{
    public function __construct(
        private CircuitBreakerManager $circuitBreakerManager
    ) {
    }

    #[ConsoleCommand(
        name: 'circuit-breaker',
        description: 'Manage circuit breakers - status, reset, health checks'
    )]
    public function execute(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $args = $input->getArguments();
        $command = $args[0] ?? 'status';

        return match ($command) {
            'status' => $this->handleStatus($input, $output),
            'stats' => $this->handleStats($input, $output),
            'health' => $this->handleHealth($input, $output),
            'reset' => $this->handleReset($input, $output),
            'config' => $this->handleConfig($input, $output),
            'export' => $this->handleExport($input, $output),
            default => $this->handleStatus($input, $output),
        };
    }

    private function handleStatus(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $args = $input->getArguments();
        $specificService = $args[1] ?? null;

        $allStatus = $this->circuitBreakerManager->getAllServicesStatus();

        if (empty($allStatus)) {
            $output->writeLine('<info>No circuit breakers configured</info>');

            return ExitCode::SUCCESS;
        }

        $output->writeLine('<info>Circuit Breaker Status</info>');
        $output->writeLine('');

        foreach ($allStatus as $namespace => $services) {
            if (empty($services)) {
                continue;
            }

            $output->writeLine("<comment>Namespace: {$namespace}</comment>");
            $output->writeLine(str_repeat('-', 50));

            foreach ($services as $service => $status) {
                if ($specificService && $service !== $specificService) {
                    continue;
                }

                $stateColor = match ($status['state']) {
                    'closed' => 'info',
                    'half_open' => 'warning',
                    'open' => 'error',
                    default => 'comment',
                };

                $output->writeLine(sprintf(
                    "  <{$stateColor}>%s</{$stateColor}> - State: <{$stateColor}>%s</{$stateColor}> | Failures: %d | Successes: %d",
                    $service,
                    strtoupper($status['state']),
                    $status['failure_count'],
                    $status['success_count']
                ));

                if ($status['last_failure_time']) {
                    $lastFailure = date('Y-m-d H:i:s', $status['last_failure_time']);
                    $output->writeLine("    Last failure: {$lastFailure}");
                }

                if ($status['configuration']) {
                    $config = $status['configuration'];
                    $output->writeLine(sprintf(
                        "    Config: Threshold=%d, Timeout=%ds, HalfOpen=%d, Success=%d",
                        $config['failure_threshold'],
                        $config['recovery_timeout_seconds'],
                        $config['half_open_max_attempts'],
                        $config['success_threshold']
                    ));
                }

                $output->writeLine('');
            }
        }

        return ExitCode::SUCCESS;
    }

    private function handleStats(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $stats = $this->circuitBreakerManager->getGlobalStatistics();

        $output->writeLine('<info>Global Circuit Breaker Statistics</info>');
        $output->writeLine('');

        $output->writeLine(sprintf('Total Services: <comment>%d</comment>', $stats['total_services']));
        $output->writeLine(sprintf('Healthy Services: <info>%d</info>', $stats['healthy_services']));
        $output->writeLine(sprintf('Degraded Services: <warning>%d</warning>', $stats['degraded_services']));
        $output->writeLine(sprintf('Failed Services: <error>%d</error>', $stats['failed_services']));
        $output->writeLine('');

        $output->writeLine('Circuit Breaker States:');
        $output->writeLine(sprintf('  Closed: <info>%d</info>', $stats['circuit_breakers_closed']));
        $output->writeLine(sprintf('  Half-Open: <warning>%d</warning>', $stats['circuit_breakers_half_open']));
        $output->writeLine(sprintf('  Open: <error>%d</error>', $stats['circuit_breakers_open']));

        return ExitCode::SUCCESS;
    }

    private function handleHealth(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $output->writeLine('<info>Performing health checks...</info>');
        $output->writeLine('');

        $healthResults = $this->circuitBreakerManager->performHealthChecks();

        foreach ($healthResults as $namespace => $services) {
            if (empty($services)) {
                continue;
            }

            $output->writeLine("<comment>Namespace: {$namespace}</comment>");

            foreach ($services as $service => $result) {
                $statusColor = match ($result['status']) {
                    'healthy' => 'info',
                    'degraded' => 'warning',
                    'failed' => 'error',
                    default => 'comment',
                };

                $output->writeLine(sprintf(
                    "  <{$statusColor}>%s</{$statusColor}> - %s (checked at %s)",
                    $service,
                    ucfirst($result['status']),
                    $result['checked_at']
                ));
            }

            $output->writeLine('');
        }

        return ExitCode::SUCCESS;
    }

    private function handleReset(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $args = $input->getArguments();
        $service = $args[1] ?? null;

        if ($service) {
            $namespace = $args[2] ?? 'default';
            $this->circuitBreakerManager->resetService($service, $namespace);
            $output->writeLine("<info>Circuit breaker for service '{$service}' in namespace '{$namespace}' has been reset</info>");
        } else {
            $confirm = $input->getOption('force') || $this->confirmReset($input, $output);

            if ($confirm) {
                $this->circuitBreakerManager->resetAll();
                $output->writeLine('<info>All circuit breakers have been reset</info>');
            } else {
                $output->writeLine('<comment>Reset cancelled</comment>');

                return ExitCode::FAILURE;
            }
        }

        return ExitCode::SUCCESS;
    }

    private function handleConfig(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $config = $this->circuitBreakerManager->exportConfiguration();

        $output->writeLine('<info>Circuit Breaker Configuration</info>');
        $output->writeLine('');

        $output->writeLine(sprintf('Circuit Breakers: %s', implode(', ', $config['circuit_breakers'])));
        $output->writeLine(sprintf('Generated: %s', $config['timestamp']));
        $output->writeLine(sprintf('Version: %s', $config['version']));
        $output->writeLine('');

        if (! empty($config['configurations'])) {
            $output->writeLine('<comment>Service Configurations:</comment>');

            foreach ($config['configurations'] as $service => $serviceConfig) {
                $output->writeLine("  {$service}:");
                $output->writeLine("    Failure Threshold: {$serviceConfig->failureThreshold}");
                $output->writeLine("    Recovery Timeout: {$serviceConfig->recoveryTimeoutSeconds}s");
                $output->writeLine("    Half-Open Max Attempts: {$serviceConfig->halfOpenMaxAttempts}");
                $output->writeLine("    Success Threshold: {$serviceConfig->successThreshold}");
                $output->writeLine('');
            }
        }

        return ExitCode::SUCCESS;
    }

    private function handleExport(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $config = $this->circuitBreakerManager->exportConfiguration();
        $json = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);

        $filename = $input->getOption('output') ?? 'circuit-breaker-config.json';

        if (file_put_contents($filename, $json) !== false) {
            $output->writeLine("<info>Configuration exported to {$filename}</info>");

            return ExitCode::SUCCESS;
        } else {
            $output->writeLine("<error>Failed to write configuration to {$filename}</error>");

            return ExitCode::FAILURE;
        }
    }

    private function confirmReset(ConsoleInput $input, ConsoleOutput $output): bool
    {
        $output->write('<warning>This will reset ALL circuit breakers. Are you sure? (y/N): </warning>');

        $handle = fopen('php://stdin', 'r');
        $response = trim(fgets($handle));
        fclose($handle);

        return strtolower($response) === 'y' || strtolower($response) === 'yes';
    }
}
