<?php

declare(strict_types=1);

namespace App\Framework\ErrorBoundaries\Middleware;

use App\Framework\ErrorBoundaries\ErrorBoundaryFactory;
use App\Framework\Http\MiddlewareManager;
use App\Framework\Http\MiddlewarePriority;
use App\Framework\Logging\Logger;

/**
 * Registry for error boundary middleware components
 */
final readonly class ErrorBoundaryMiddlewareRegistry
{
    public function __construct(
        private MiddlewareManager $middlewareManager,
        private ErrorBoundaryFactory $boundaryFactory,
        private MiddlewareConfiguration $configuration,
        private ?Logger $logger = null,
    ) {
    }

    /**
     * Register all error boundary middleware
     */
    public function registerAll(): void
    {
        $this->registerMainMiddleware();

        if ($this->configuration->enableApiMiddleware) {
            $this->registerApiMiddleware();
        }

        if ($this->configuration->enableHealthMiddleware) {
            $this->registerHealthMiddleware();
        }
    }

    /**
     * Register main error boundary middleware
     */
    public function registerMainMiddleware(): void
    {
        $middleware = new ErrorBoundaryMiddleware(
            boundaryFactory: $this->boundaryFactory,
            logger: $this->logger,
        );

        $this->middlewareManager->register(
            middleware: $middleware,
            priority: $this->configuration->priority,
            condition: fn ($request) => $this->shouldApplyMainMiddleware($request),
        );
    }

    /**
     * Register API-specific error boundary middleware
     */
    public function registerApiMiddleware(): void
    {
        $middleware = new ApiErrorBoundaryMiddleware(
            boundaryFactory: $this->boundaryFactory,
            logger: $this->logger,
            includeDebugInfo: $this->configuration->includeDebugInfo,
        );

        $this->middlewareManager->register(
            middleware: $middleware,
            priority: $this->configuration->priority + 10, // Higher priority for API
            condition: fn ($request) => $this->shouldApplyApiMiddleware($request),
        );
    }

    /**
     * Register health check middleware
     */
    public function registerHealthMiddleware(): void
    {
        $middleware = new CircuitBreakerHealthMiddleware(
            boundaryFactory: $this->boundaryFactory,
            monitoredBoundaries: $this->getMonitoredBoundaries(),
        );

        $this->middlewareManager->register(
            middleware: $middleware,
            priority: MiddlewarePriority::HIGH, // Health checks should run early
            condition: fn ($request) => $this->shouldApplyHealthMiddleware($request),
        );
    }

    /**
     * Register middleware with custom configuration
     */
    public function registerCustom(
        string $middlewareClass,
        array $constructorArgs,
        int $priority,
        ?callable $condition = null
    ): void {
        $middleware = new $middlewareClass(...$constructorArgs);

        $this->middlewareManager->register(
            middleware: $middleware,
            priority: $priority,
            condition: $condition,
        );
    }

    /**
     * Check if main middleware should be applied
     */
    private function shouldApplyMainMiddleware($request): bool
    {
        $path = $request->uri->getPath();

        // Don't apply to health endpoints (they have their own middleware)
        if ($this->configuration->isHealthPath($path)) {
            return false;
        }

        // Don't apply to API endpoints if API middleware is enabled
        if ($this->configuration->enableApiMiddleware && $this->configuration->isApiPath($path)) {
            return false;
        }

        return $this->configuration->shouldEnableForRoute($path);
    }

    /**
     * Check if API middleware should be applied
     */
    private function shouldApplyApiMiddleware($request): bool
    {
        $path = $request->uri->getPath();

        return $this->configuration->isApiPath($path) &&
               $this->configuration->shouldEnableForRoute($path);
    }

    /**
     * Check if health middleware should be applied
     */
    private function shouldApplyHealthMiddleware($request): bool
    {
        $path = $request->uri->getPath();

        return $this->configuration->isHealthPath($path);
    }

    /**
     * Get list of boundaries to monitor for health checks
     */
    private function getMonitoredBoundaries(): array
    {
        return [
            'api_health',
            'database_connection',
            'external_payment_service',
            'external_email_service',
            'cache_service',
            'file_storage',
            'mail_service',
            'notification_service',
            'search_service',
            'analytics_service',
        ];
    }

    /**
     * Unregister all error boundary middleware
     */
    public function unregisterAll(): void
    {
        $this->middlewareManager->unregister(ErrorBoundaryMiddleware::class);
        $this->middlewareManager->unregister(ApiErrorBoundaryMiddleware::class);
        $this->middlewareManager->unregister(CircuitBreakerHealthMiddleware::class);
    }

    /**
     * Get middleware statistics
     */
    public function getStatistics(): array
    {
        return [
            'configuration' => [
                'enable_for_all_routes' => $this->configuration->enableForAllRoutes,
                'enabled_routes_count' => count($this->configuration->enabledRoutes),
                'excluded_routes_count' => count($this->configuration->excludedRoutes),
                'api_middleware_enabled' => $this->configuration->enableApiMiddleware,
                'health_middleware_enabled' => $this->configuration->enableHealthMiddleware,
                'debug_info_enabled' => $this->configuration->includeDebugInfo,
            ],
            'middleware_registered' => [
                'main_middleware' => $this->middlewareManager->isRegistered(ErrorBoundaryMiddleware::class),
                'api_middleware' => $this->middlewareManager->isRegistered(ApiErrorBoundaryMiddleware::class),
                'health_middleware' => $this->middlewareManager->isRegistered(CircuitBreakerHealthMiddleware::class),
            ],
            'monitored_boundaries_count' => count($this->getMonitoredBoundaries()),
        ];
    }
}
