<?php

declare(strict_types=1);

namespace Tests\Framework\Http;

use App\Framework\DI\DefaultContainer;
use App\Framework\Http\MiddlewareDependencyResolver;
use App\Framework\Reflection\CachedReflectionProvider;
use PHPUnit\Framework\TestCase;

/**
 * Integration test for MiddlewareDependencyResolver with real system components
 */
final class MiddlewareDependencyResolverIntegrationTest extends TestCase
{
    private MiddlewareDependencyResolver $resolver;

    private array $testLog = [];

    protected function setUp(): void
    {
        $container = new DefaultContainer();
        $reflectionProvider = new CachedReflectionProvider();

        // Create a test logger that captures logs
        $logger = new class ($this->testLog) implements \App\Framework\Logging\Logger {
            public function __construct(private array &$logCapture)
            {
            }

            public function debug(string $message, array $context = []): void
            {
                $this->logCapture[] = ['level' => 'debug', 'message' => $message, 'context' => $context];
            }

            public function info(string $message, array $context = []): void
            {
                $this->logCapture[] = ['level' => 'info', 'message' => $message, 'context' => $context];
            }

            public function notice(string $message, array $context = []): void
            {
                $this->logCapture[] = ['level' => 'notice', 'message' => $message, 'context' => $context];
            }

            public function warning(string $message, array $context = []): void
            {
                $this->logCapture[] = ['level' => 'warning', 'message' => $message, 'context' => $context];
            }

            public function error(string $message, array $context = []): void
            {
                $this->logCapture[] = ['level' => 'error', 'message' => $message, 'context' => $context];
            }

            public function critical(string $message, array $context = []): void
            {
                $this->logCapture[] = ['level' => 'critical', 'message' => $message, 'context' => $context];
            }

            public function alert(string $message, array $context = []): void
            {
                $this->logCapture[] = ['level' => 'alert', 'message' => $message, 'context' => $context];
            }

            public function emergency(string $message, array $context = []): void
            {
                $this->logCapture[] = ['level' => 'emergency', 'message' => $message, 'context' => $context];
            }

            public function log(\App\Framework\Logging\LogLevel $level, string $message, array $context = []): void
            {
                $this->logCapture[] = ['level' => $level->value, 'message' => $message, 'context' => $context];
            }
        };

        $this->resolver = new MiddlewareDependencyResolver(
            $reflectionProvider,
            $container,
            $logger
        );
    }

    public function test_resolves_existing_middlewares_and_filters_missing_ones(): void
    {
        $middlewares = [
            // Critical middlewares (required by resolver)
            \App\Framework\Http\Middlewares\ExceptionHandlingMiddleware::class,
            \App\Framework\Http\Middlewares\RequestIdMiddleware::class,
            \App\Framework\Http\Middlewares\RoutingMiddleware::class,

            // Additional middlewares to test
            \App\Framework\Http\Middlewares\AuthMiddleware::class,

            // This doesn't exist
            'NonExistentMiddleware',

            // This might have missing dependencies
            \App\Framework\Http\Middlewares\ResponseGeneratorMiddleware::class,
        ];

        $result = $this->resolver->resolve($middlewares);

        // Should have some middlewares resolved (at least the simple ones)
        $this->assertGreaterThan(0, count($result->getMiddlewares()));

        // Check that logging happened
        $logMessages = array_column($this->testLog, 'message');
        $combinedLog = implode(' ', $logMessages);
        $this->assertStringContainsString(
            'Class not found: NonExistentMiddleware',
            $combinedLog
        );

        // Should log start and completion
        $this->assertStringContainsString('Starting resolution for', implode(' ', $logMessages));
        $this->assertStringContainsString('Resolution completed with', implode(' ', $logMessages));
    }

    public function test_identifies_middlewares_with_missing_dependencies(): void
    {
        // Test a middleware that likely has dependencies
        $middlewares = [
            // Critical middlewares (required by resolver)
            \App\Framework\Http\Middlewares\ExceptionHandlingMiddleware::class,
            \App\Framework\Http\Middlewares\RequestIdMiddleware::class,
            \App\Framework\Http\Middlewares\RoutingMiddleware::class,

            \App\Framework\Http\Middlewares\ResponseGeneratorMiddleware::class,
        ];

        $result = $this->resolver->resolve($middlewares);

        // Check if there are warnings about missing dependencies
        $warningMessages = array_filter($this->testLog, fn ($log) => $log['level'] === 'warning');

        if (count($result->getMiddlewares()) === 0) {
            // If middleware was filtered out, should have warning about missing dependencies
            $warningText = implode(' ', array_column($warningMessages, 'message'));
            $this->assertStringContainsString('Missing dependencies for ResponseGeneratorMiddleware', $warningText);
        }
    }

    public function test_logs_middleware_resolution_statistics(): void
    {
        $middlewares = [
            // Critical middlewares (required by resolver)
            \App\Framework\Http\Middlewares\ExceptionHandlingMiddleware::class,
            \App\Framework\Http\Middlewares\RequestIdMiddleware::class,
            \App\Framework\Http\Middlewares\RoutingMiddleware::class,

            \App\Framework\Http\Middlewares\AuthMiddleware::class,
            'NonExistentMiddleware1',
            'NonExistentMiddleware2',
        ];

        $result = $this->resolver->resolve($middlewares);

        // Extract log messages
        $logMessages = array_column($this->testLog, 'message');
        $combinedLog = implode(' ', $logMessages);

        // Should log how many middlewares we started with (only existing ones are counted)
        $this->assertStringContainsString('Starting resolution for 4 middlewares', $combinedLog);

        // Should log how many we ended up with
        $this->assertStringContainsString('Resolution completed with', $combinedLog);

        // Should have warnings about non-existent classes
        $this->assertStringContainsString('Class not found: NonExistentMiddleware1', $combinedLog);
        $this->assertStringContainsString('Class not found: NonExistentMiddleware2', $combinedLog);
    }

    public function test_dependency_graph_information(): void
    {
        $middlewares = [
            // Critical middlewares (required by resolver)
            \App\Framework\Http\Middlewares\ExceptionHandlingMiddleware::class,
            \App\Framework\Http\Middlewares\RequestIdMiddleware::class,
            \App\Framework\Http\Middlewares\RoutingMiddleware::class,

            \App\Framework\Http\Middlewares\AuthMiddleware::class,
        ];

        $result = $this->resolver->resolve($middlewares);
        $dependencyInfo = $this->resolver->getDependencyInfo($middlewares);

        // Should have dependency information for each middleware
        $this->assertArrayHasKey(\App\Framework\Http\Middlewares\RequestIdMiddleware::class, $dependencyInfo);
        $this->assertArrayHasKey(\App\Framework\Http\Middlewares\AuthMiddleware::class, $dependencyInfo);

        // Each entry should have expected structure
        foreach ($dependencyInfo as $className => $info) {
            if (isset($info['error'])) {
                continue; // Skip errored ones
            }

            $this->assertArrayHasKey('short_name', $info);
            $this->assertArrayHasKey('exists', $info);
            $this->assertArrayHasKey('can_instantiate', $info);
        }
    }
}
