<?php

declare(strict_types=1);

namespace App\Framework\ErrorBoundaries\Middleware;

use App\Framework\ErrorBoundaries\ErrorBoundaryFactory;
use App\Framework\Http\HttpMiddleware;
use App\Framework\Http\MiddlewareContext;
use App\Framework\Http\Next;
use App\Framework\Http\RequestStateManager;
use App\Framework\Http\Responses\JsonResponse;
use App\Framework\Http\Status;

/**
 * Middleware that provides circuit breaker health information
 */
final readonly class CircuitBreakerHealthMiddleware implements HttpMiddleware
{
    public function __construct(
        private ErrorBoundaryFactory $boundaryFactory,
        private array $monitoredBoundaries = [],
    ) {
    }

    public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
    {
        $request = $context->request;

        // Only handle health check requests
        if (! $this->isHealthCheckRequest($request)) {
            return $next($context, $stateManager);
        }

        return $context->withResponse($this->createHealthResponse());
    }

    /**
     * Check if this is a health check request
     */
    private function isHealthCheckRequest($request): bool
    {
        $path = $request->uri->getPath();

        return in_array($path, [
            '/health/circuit-breakers',
            '/api/health/circuit-breakers',
            '/admin/health/circuit-breakers',
        ], true);
    }

    /**
     * Create comprehensive health response
     */
    private function createHealthResponse(): JsonResponse
    {
        $boundaries = $this->getMonitoredBoundaries();
        $healthData = [];
        $overallHealth = 'healthy';
        $unhealthyCount = 0;

        foreach ($boundaries as $boundaryName) {
            $boundary = $this->boundaryFactory->create($boundaryName, \App\Framework\ErrorBoundaries\BoundaryConfig::development());
            $health = $boundary->getCircuitHealth();

            if ($health !== null) {
                $healthData[$boundaryName] = $health;

                if (! $health['is_healthy']) {
                    $unhealthyCount++;
                    if ($health['severity'] === 'error') {
                        $overallHealth = 'critical';
                    } elseif ($overallHealth === 'healthy') {
                        $overallHealth = 'warning';
                    }
                }
            }
        }

        $response = [
            'status' => $overallHealth,
            'timestamp' => date(\DateTimeInterface::ISO8601),
            'summary' => [
                'total_boundaries' => count($boundaries),
                'healthy_boundaries' => count($boundaries) - $unhealthyCount,
                'unhealthy_boundaries' => $unhealthyCount,
                'overall_health_score' => $this->calculateHealthScore($healthData),
            ],
            'boundaries' => $healthData,
            'recommendations' => $this->generateRecommendations($healthData),
        ];

        $statusCode = match ($overallHealth) {
            'healthy' => Status::OK,
            'warning' => Status::OK, // Still OK but with warnings
            'critical' => Status::SERVICE_UNAVAILABLE,
            default => Status::OK,
        };

        return new JsonResponse($response, $statusCode);
    }

    /**
     * Get list of boundaries to monitor
     */
    private function getMonitoredBoundaries(): array
    {
        if (! empty($this->monitoredBoundaries)) {
            return $this->monitoredBoundaries;
        }

        // Default boundaries to monitor
        return [
            'api_health',
            'database_connection',
            'external_payment_service',
            'external_email_service',
            'cache_service',
            'file_storage',
        ];
    }

    /**
     * Calculate overall health score (0-100)
     */
    private function calculateHealthScore(array $healthData): int
    {
        if (empty($healthData)) {
            return 100;
        }

        $totalScore = 0;
        $count = 0;

        foreach ($healthData as $health) {
            $boundaryScore = match ($health['severity']) {
                'info' => 100,  // Healthy
                'warning' => 70, // Warning
                'error' => 20,   // Critical
                default => 50,   // Unknown
            };

            $totalScore += $boundaryScore;
            $count++;
        }

        return $count > 0 ? (int) round($totalScore / $count) : 100;
    }

    /**
     * Generate actionable recommendations based on health data
     */
    private function generateRecommendations(array $healthData): array
    {
        $recommendations = [];

        foreach ($healthData as $boundaryName => $health) {
            if (! $health['is_healthy']) {
                $recommendation = $this->getRecommendationForBoundary($boundaryName, $health);
                if ($recommendation !== null) {
                    $recommendations[] = $recommendation;
                }
            }
        }

        // Add general recommendations
        if (count($recommendations) > 3) {
            $recommendations[] = [
                'type' => 'general',
                'priority' => 'high',
                'message' => 'Multiple circuit breakers are unhealthy. Consider system-wide health check.',
                'action' => 'Review system load and dependencies',
            ];
        }

        return $recommendations;
    }

    /**
     * Get specific recommendation for a boundary
     */
    private function getRecommendationForBoundary(string $boundaryName, array $health): ?array
    {
        $recommendations = [
            'database_connection' => [
                'type' => 'database',
                'priority' => 'critical',
                'message' => 'Database connection circuit breaker is open',
                'action' => 'Check database connectivity and performance',
            ],
            'external_payment_service' => [
                'type' => 'external_service',
                'priority' => 'high',
                'message' => 'Payment service circuit breaker is failing',
                'action' => 'Verify payment service status and API connectivity',
            ],
            'cache_service' => [
                'type' => 'cache',
                'priority' => 'medium',
                'message' => 'Cache service circuit breaker is degraded',
                'action' => 'Check Redis/cache service health and memory usage',
            ],
        ];

        $recommendation = $recommendations[$boundaryName] ?? null;

        if ($recommendation !== null) {
            $recommendation['boundary'] = $boundaryName;
            $recommendation['state'] = $health['state'];
            $recommendation['failure_count'] = $health['failure_count'];
        }

        return $recommendation;
    }
}
