<?php

declare(strict_types=1);

use App\Framework\Core\DynamicRoute;
use App\Framework\Core\StaticRoute;
use App\Framework\Http\HttpRequest;
use App\Framework\Http\Method;
use App\Framework\Http\Request;
use App\Framework\Router\CompiledRoutes;
use App\Framework\Router\HttpRouter;
use App\Framework\Router\NoRouteMatch;
use App\Framework\Router\RouteContext;
use App\Framework\Router\RouteMatchSuccess;

beforeEach(function () {
    // Create test routes
    $this->staticRoutes = [
        '/home' => new StaticRoute(
            controller: 'HomeController',
            action: 'index',
            parameters: [],
            name: 'home',
            path: '/home'
        ),
        '/api/status' => new StaticRoute(
            controller: 'StatusController',
            action: 'check',
            parameters: [],
            name: 'status',
            path: '/api/status'
        ),
    ];

    // Create properly structured static routes for CompiledRoutes
    $staticRoutes = [
        'GET' => [
            '/home' => $this->staticRoutes['/home'],
            '/api/status' => $this->staticRoutes['/api/status'],
        ],
    ];

    $this->compiledRoutes = new CompiledRoutes(
        staticRoutes: $staticRoutes,
        dynamicPatterns: [],
        namedRoutes: []
    );

    $this->router = new HttpRouter($this->compiledRoutes);

    // Create test request
    $this->request = new HttpRequest(
        method: Method::GET,
        path: '/home'
    );
});

it('matches static route successfully', function () {
    $context = $this->router->match($this->request);

    expect($context)->toBeInstanceOf(RouteContext::class);
    expect($context->match)->toBeInstanceOf(RouteMatchSuccess::class);
    expect($context->method)->toBe(Method::GET);
    expect($context->path)->toBe('/home');

    $matchedRoute = $context->match->route;
    expect($matchedRoute)->toBeInstanceOf(StaticRoute::class);
    expect($matchedRoute->path)->toBe('/home');
    expect($matchedRoute->controller)->toBe('HomeController');
    expect($matchedRoute->action)->toBe('index');
});

it('matches different static route', function () {
    $request = new HttpRequest(method: Method::GET, path: '/api/status');

    $context = $this->router->match($request);

    expect($context->match)->toBeInstanceOf(RouteMatchSuccess::class);
    $matchedRoute = $context->match->route;
    expect($matchedRoute->path)->toBe('/api/status');
    expect($matchedRoute->controller)->toBe('StatusController');
    expect($matchedRoute->action)->toBe('check');
});

it('returns NoRouteMatch for non-existent route', function () {
    $request = new HttpRequest(method: Method::GET, path: '/non-existent');

    $context = $this->router->match($request);

    expect($context->match)->toBeInstanceOf(NoRouteMatch::class);
    expect($context->path)->toBe('/non-existent');
});

it('creates correct route context', function () {
    $context = $this->router->match($this->request);

    expect($context->method)->toBe(Method::GET);
    expect($context->path)->toBe('/home');
    expect($context->match)->toBeInstanceOf(RouteMatchSuccess::class);
});

it('handles different HTTP methods', function () {
    $request = new HttpRequest(method: Method::POST, path: '/home');

    $context = $this->router->match($request);

    // POST method should not match GET route
    expect($context->match)->toBeInstanceOf(NoRouteMatch::class);
});

it('router has optimized routes', function () {
    expect($this->router->optimizedRoutes)->toBe($this->compiledRoutes);
});

it('static routes take precedence over dynamic routes', function () {
    // This test verifies that static routes are checked first
    $context = $this->router->match($this->request);

    expect($context->match)->toBeInstanceOf(RouteMatchSuccess::class);
    // If this was a dynamic route match, it would be a DynamicRoute
    expect($context->match->route)->toBeInstanceOf(StaticRoute::class);
});
