<?php

declare(strict_types=1);

use App\Framework\Attributes\Route;
use App\Framework\Core\DynamicRoute;
use App\Framework\Core\RouteCompiler;
use App\Framework\Discovery\Visitors\UnifiedRouteVisitor;
use App\Framework\Router\Result\FileResult;
use App\Framework\Router\Result\JsonResult;

// Test Controller Klassen für Dynamic Routing Tests
class TestDynamicController
{
    #[Route('/test/{id}')]
    public function showById(int $id): JsonResult
    {
        return new JsonResult(['id' => $id]);
    }

    #[Route('/images/{filename}')]
    public function showImage(string $filename): FileResult
    {
        return new FileResult("/path/to/{$filename}");
    }

    #[Route('/user/{userId}/post/{postId}')]
    public function showUserPost(int $userId, string $postId): JsonResult
    {
        return new JsonResult(['userId' => $userId, 'postId' => $postId]);
    }

    #[Route('/api/search/{query?}')]
    public function search(?string $query = null): JsonResult
    {
        return new JsonResult(['query' => $query]);
    }
}

describe('Dynamic Routing Parameter Extraction', function () {
    beforeEach(function () {
        $this->discoveryVisitor = new UnifiedRouteVisitor();
        $this->routeCompiler = new RouteCompiler();
    });

    test('discovers routes with dynamic parameters', function () {
        $this->discoveryVisitor->onScanStart();
        // UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
        $className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
        $filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
        $reflection = new \App\Framework\Reflection\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));

        $this->discoveryVisitor->visitClass($className, $filePath, $reflection);

        $routes = $this->discoveryVisitor->getResults();

        expect($routes)->toHaveCount(4);

        // Test route with single parameter
        $singleParamRoute = null;
        foreach ($routes as $route) {
            if ($route['path'] === '/test/{id}') {
                $singleParamRoute = $route;

                break;
            }
        }
        expect($singleParamRoute)->not->toBeNull();
        expect($singleParamRoute['controller'])->toBe(TestDynamicController::class);
        expect($singleParamRoute['action'])->toBe('showById');

        // Test image route (the problematic one)
        $imageRoute = null;
        foreach ($routes as $route) {
            if ($route['path'] === '/images/{filename}') {
                $imageRoute = $route;

                break;
            }
        }
        expect($imageRoute)->not->toBeNull();
        expect($imageRoute['controller'])->toBe(TestDynamicController::class);
        expect($imageRoute['action'])->toBe('showImage');

        // Test route with multiple parameters
        $multiParamRoute = null;
        foreach ($routes as $route) {
            if ($route['path'] === '/user/{userId}/post/{postId}') {
                $multiParamRoute = $route;

                break;
            }
        }
        expect($multiParamRoute)->not->toBeNull();
    });

    test('extracts parameter information correctly', function () {
        $this->discoveryVisitor->onScanStart();
        // UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
        $className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
        $filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
        $reflection = new \App\Framework\Reflection\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));

        $this->discoveryVisitor->visitClass($className, $filePath, $reflection);

        $routes = $this->discoveryVisitor->getResults();

        // Suche die Image Route
        $imageRoute = null;
        foreach ($routes as $route) {
            if ($route['path'] === '/images/{filename}') {
                $imageRoute = $route;

                break;
            }
        }

        // Prüfe ob Parameter-Informationen vorhanden sind
        if (isset($imageRoute['parameters'])) {
            expect($imageRoute['parameters'])->toBeArray();

            // Debug: Zeige Parameter-Struktur
            error_log('Image Route Parameters: ' . json_encode($imageRoute['parameters']));

            // Suche nach filename Parameter
            $filenameParam = null;
            foreach ($imageRoute['parameters'] as $param) {
                if ($param['name'] === 'filename') {
                    $filenameParam = $param;

                    break;
                }
            }

            if ($filenameParam) {
                expect($filenameParam['name'])->toBe('filename');
                expect($filenameParam['type'])->toBe('string'); // Das ist wahrscheinlich null!
                expect($filenameParam['isBuiltin'])->toBeTrue();
            } else {
                error_log('Filename parameter not found in parameters array');
            }
        } else {
            error_log('No parameters found in route array');
            expect($imageRoute)->toHaveKey('parameters'); // Dieser Test wird wahrscheinlich fehlschlagen
        }
    });

    test('compiles dynamic routes with parameter names', function () {
        $this->discoveryVisitor->onScanStart();
        // UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
        $className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
        $filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
        $reflection = new \App\Framework\Reflection\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));

        $this->discoveryVisitor->visitClass($className, $filePath, $reflection);

        $routes = $this->discoveryVisitor->getResults();
        $compiledRoutes = $this->routeCompiler->compile($routes);

        // Prüfe GET routes
        expect($compiledRoutes)->toHaveKey('GET');
        expect($compiledRoutes['GET'])->toHaveKey('dynamic');

        $dynamicRoutes = $compiledRoutes['GET']['dynamic'];
        expect($dynamicRoutes)->toBeArray();
        expect(count($dynamicRoutes))->toBeGreaterThan(0);

        // Suche Image Route in compilierten Routes
        $imageRoute = null;
        foreach ($dynamicRoutes as $route) {
            if ($route instanceof DynamicRoute && $route->path === '/images/{filename}') {
                $imageRoute = $route;

                break;
            }
        }

        expect($imageRoute)->not->toBeNull();
        expect($imageRoute)->toBeInstanceOf(DynamicRoute::class);

        // Prüfe Parameter Names
        expect($imageRoute->paramNames)->toBe(['filename']);

        // Prüfe compiled regex
        expect($imageRoute->regex)->toBeString();
        expect($imageRoute->regex)->toMatch('/^~.*\/images\/.*\$~/'); // Regex für /images/{filename}

        // Prüfe Parameter Details
        error_log('Compiled Image Route Parameters: ' . json_encode($imageRoute->parameters));

        if (! empty($imageRoute->parameters)) {
            $filenameParam = null;
            foreach ($imageRoute->parameters as $param) {
                if ($param['name'] === 'filename') {
                    $filenameParam = $param;

                    break;
                }
            }

            if ($filenameParam) {
                expect($filenameParam['type'])->not->toBeNull(); // Das sollte nicht null sein!
                expect($filenameParam['type'])->toBe('string');
            }
        }
    });

    test('handles multiple parameter types correctly', function () {
        $this->discoveryVisitor->onScanStart();
        // UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
        $className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
        $filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
        $reflection = new \App\Framework\Reflection\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));

        $this->discoveryVisitor->visitClass($className, $filePath, $reflection);

        $routes = $this->discoveryVisitor->getResults();

        // Test verschiedene Parameter-Typen
        $userPostRoute = null;
        foreach ($routes as $route) {
            if ($route['path'] === '/user/{userId}/post/{postId}') {
                $userPostRoute = $route;

                break;
            }
        }

        if (isset($userPostRoute['parameters'])) {
            $parameters = $userPostRoute['parameters'];

            // Suche nach userId (int) und postId (string) Parametern
            $userIdParam = null;
            $postIdParam = null;
            foreach ($parameters as $param) {
                if ($param['name'] === 'userId') {
                    $userIdParam = $param;
                } elseif ($param['name'] === 'postId') {
                    $postIdParam = $param;
                }
            }

            if ($userIdParam) {
                expect($userIdParam['type'])->toBe('int');
                expect($userIdParam['isBuiltin'])->toBeTrue();
            }

            if ($postIdParam) {
                expect($postIdParam['type'])->toBe('string');
                expect($postIdParam['isBuiltin'])->toBeTrue();
            }
        }
    });

    test('handles optional parameters correctly', function () {
        $this->discoveryVisitor->onScanStart();
        // UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
        $className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
        $filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
        $reflection = new \App\Framework\Reflection\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));

        $this->discoveryVisitor->visitClass($className, $filePath, $reflection);

        $routes = $this->discoveryVisitor->getResults();

        // Test optionale Parameter
        $searchRoute = null;
        foreach ($routes as $route) {
            if ($route['path'] === '/api/search/{query?}') {
                $searchRoute = $route;

                break;
            }
        }

        if (isset($searchRoute['parameters'])) {
            $parameters = $searchRoute['parameters'];

            $queryParam = null;
            foreach ($parameters as $param) {
                if ($param['name'] === 'query') {
                    $queryParam = $param;

                    break;
                }
            }

            if ($queryParam) {
                expect($queryParam['type'])->toBe('string');
                expect($queryParam['isOptional'])->toBeTrue();
                expect($queryParam['hasDefault'])->toBeTrue();
                expect($queryParam['default'])->toBeNull();
            }
        }
    });
});

describe('Dynamic Route Parameter Processing Debug', function () {
    test('shows current parameter extraction workflow', function () {
        $discoveryVisitor = new UnifiedRouteVisitor();
        $discoveryVisitor->onScanStart();
        $className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
        $filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
        $reflection = new \App\Framework\Reflection\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));

        $discoveryVisitor->visitClass($className, $filePath, $reflection);

        $routes = $discoveryVisitor->getResults();

        // Debug: Zeige alle gefundenen Routes
        error_log('=== All discovered routes ===');
        foreach ($routes as $i => $route) {
            error_log("Route {$i}: " . json_encode([
                'path' => $route['path'],
                'controller' => $route['controller'],
                'action' => $route['action'],
                'has_parameters' => isset($route['parameters']),
                'parameter_count' => isset($route['parameters']) ? count($route['parameters']) : 0,
            ]));

            if (isset($route['parameters'])) {
                foreach ($route['parameters'] as $j => $param) {
                    error_log("  Parameter {$j}: " . json_encode($param));
                }
            }
        }

        // Debug: Zeige RouteDiscoveryVisitor interne Struktur
        error_log('=== RouteDiscoveryVisitor internals ===');
        // Wir können nicht auf private Properties zugreifen, aber wir können testen

        expect(true)->toBeTrue(); // Placeholder - der Test ist für Debug-Zwecke
    });
});
