<?php

declare(strict_types=1);

namespace App\Framework\ErrorBoundaries\Middleware;

use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\ErrorBoundaries\ErrorBoundaryFactory;
use App\Framework\Http\MiddlewareManager;
use App\Framework\Logging\Logger;

/**
 * Service provider for error boundary middleware
 */
final readonly class MiddlewareServiceProvider
{
    public function __construct(
        private MiddlewareConfiguration $configuration,
    ) {
    }

    #[Initializer]
    public function initialize(Container $container): void
    {
        $this->registerMiddlewareConfiguration($container);
        $this->registerMiddlewareComponents($container);
        $this->registerMiddlewareRegistry($container);
        $this->initializeMiddleware($container);
    }

    /**
     * Register middleware configuration
     */
    private function registerMiddlewareConfiguration(Container $container): void
    {
        $container->bindInstance(
            MiddlewareConfiguration::class,
            $this->configuration
        );
    }

    /**
     * Register middleware components
     */
    private function registerMiddlewareComponents(Container $container): void
    {
        // Register main error boundary middleware
        $container->bind(
            ErrorBoundaryMiddleware::class,
            function (Container $container) {
                return new ErrorBoundaryMiddleware(
                    boundaryFactory: $container->get(ErrorBoundaryFactory::class),
                    logger: $container->getOptional(Logger::class),
                );
            }
        );

        // Register API error boundary middleware
        $container->bind(
            ApiErrorBoundaryMiddleware::class,
            function (Container $container) {
                $config = $container->get(MiddlewareConfiguration::class);

                return new ApiErrorBoundaryMiddleware(
                    boundaryFactory: $container->get(ErrorBoundaryFactory::class),
                    logger: $container->getOptional(Logger::class),
                    includeDebugInfo: $config->includeDebugInfo,
                );
            }
        );

        // Register circuit breaker health middleware
        $container->bind(
            CircuitBreakerHealthMiddleware::class,
            function (Container $container) {
                return new CircuitBreakerHealthMiddleware(
                    boundaryFactory: $container->get(ErrorBoundaryFactory::class),
                    monitoredBoundaries: $this->getDefaultMonitoredBoundaries(),
                );
            }
        );
    }

    /**
     * Register middleware registry
     */
    private function registerMiddlewareRegistry(Container $container): void
    {
        $container->bind(
            ErrorBoundaryMiddlewareRegistry::class,
            function (Container $container) {
                return new ErrorBoundaryMiddlewareRegistry(
                    middlewareManager: $container->get(MiddlewareManager::class),
                    boundaryFactory: $container->get(ErrorBoundaryFactory::class),
                    configuration: $container->get(MiddlewareConfiguration::class),
                    logger: $container->getOptional(Logger::class),
                );
            }
        );
    }

    /**
     * Initialize and register middleware
     */
    private function initializeMiddleware(Container $container): void
    {
        // Get the registry and register all middleware
        $registry = $container->get(ErrorBoundaryMiddlewareRegistry::class);
        $registry->registerAll();
    }

    /**
     * Create service provider with development configuration
     */
    public static function development(): self
    {
        return new self(MiddlewareConfiguration::development());
    }

    /**
     * Create service provider with production configuration
     */
    public static function production(): self
    {
        return new self(MiddlewareConfiguration::production());
    }

    /**
     * Create service provider with API-only configuration
     */
    public static function apiOnly(): self
    {
        return new self(MiddlewareConfiguration::apiOnly());
    }

    /**
     * Create service provider with custom configuration
     */
    public static function custom(MiddlewareConfiguration $configuration): self
    {
        return new self($configuration);
    }

    /**
     * Get default monitored boundaries
     */
    private function getDefaultMonitoredBoundaries(): array
    {
        return [
            'api_health',
            'database_connection',
            'external_payment_service',
            'external_email_service',
            'cache_service',
            'file_storage',
            'mail_service',
            'notification_service',
            'search_service',
            'analytics_service',
        ];
    }
}
