<?php

declare(strict_types=1);

namespace App\Framework\Router;

use App\Framework\Core\DynamicRoute;
use App\Framework\DI\DefaultContainer;
use App\Framework\Http\Response;
use App\Framework\Http\Responses\NotFound;
use App\Framework\Performance\Contracts\PerformanceServiceInterface;
use App\Framework\Performance\PerformanceCategory;

final readonly class RouteDispatcher
{
    public function __construct(
        private DefaultContainer   $container,
        private ParameterProcessor $parameterProcessor,
        private PerformanceServiceInterface $performanceService
    ) {
    }

    /**
     * Verarbeitet eine Route und führt die entsprechende Controller-Action aus
     */
    public function dispatch(RouteContext $routeContext): ActionResult|Response
    {
        $routeMatch = $routeContext->match;

        if ($routeMatch->isMatch()) {
            /** @var RouteMatchSuccess $routeMatch */
            return $this->executeController($routeMatch);
        }

        return new NotFound();
    }

    /**
     * Führt die Controller-Action mit den aufbereiteten Parametern aus
     * @param RouteMatchSuccess $routeMatch
     * @return ActionResult|Response
     */
    private function executeController(RouteMatch $routeMatch): ActionResult|Response
    {
        $controller = $routeMatch->route->controller;
        $action = $routeMatch->route->action;

        $queryParams = [];
        if ($routeMatch->route instanceof DynamicRoute) {
            $queryParams = $routeMatch->route->paramValues;
        }

        // Use type-safe parameter collection if available, fallback to legacy array
        $parameterCollection = $routeMatch->route->getParameterCollection();
        $preparedParams = $this->performanceService->measure(
            'parameter_preparation',
            fn () => $this->parameterProcessor->prepareParametersFromCollection($parameterCollection, $queryParams),
            PerformanceCategory::CONTROLLER,
            [
                'controller' => $controller,
                'action' => $action,
                'param_count' => $parameterCollection->count(),
            ]
        );

        // Measure controller instantiation
        $controllerInstance = $this->performanceService->measure(
            'controller_instantiation',
            fn () => $this->container->get($controller), /** @phpstan-ignore argument.type */
            PerformanceCategory::CONTROLLER,
            ['controller' => $controller]
        );

        // Measure actual controller method execution
        $result = $this->performanceService->measure(
            'controller_execution',
            fn () => $controllerInstance->$action(...$preparedParams),
            PerformanceCategory::CONTROLLER,
            [
                'controller' => $controller,
                'action' => $action,
            ]
        );

        if ($result instanceof Response || $result instanceof ActionResult) {
            return $result;
        }

        // Wenn kein gültiges Result zurückgegeben wird
        return new NotFound('Ungültige Antwort vom Controller');
    }
}
