<?php

namespace Licenzo\Framework\Http\Router;

use Licenzo\Framework\Foundation\Application;
use Licenzo\Framework\Http\Request;
use Licenzo\Framework\Http\Middleware\Pipeline;

class RouteResolver
{
    protected Application $app;
    protected Route $route;
    protected array $middlewareInstances = [];
    protected ?Request $request = null;

    public function __construct(Application $app, Route $route)
    {
        $this->app = $app;
        $this->route = $route;
    }

    public function dispatch()
    {
        try {
            $context = $this->app->make('request.context');

            // 1. Get WordPress request from app context
            $wpRequest = $this->app->bound('current.wp.request')
                ? $this->app->make('current.wp.request')
                : null;

            // 2. Create framework Request
            $this->request = Request::createFromWordPressRequest($wpRequest);
            $context->setRequest($this->request);
            $context->setRoute($this->route);

            // 3. Resolve middleware (global + route-specific)
            $this->resolveMiddlewares();

            // 4. Run through pipeline
            $response = $this->runThroughMiddleware();

            // 5. Store response in context
            $context->setResponse($response);

            // 6. Return response
            return $response;

        } catch (\Throwable $e) {
            // Single point for error conversion
            return $this->handleException($e);
        }
    }

    protected function resolveMiddlewares()
    {
        $registry = $this->app->make('middleware.registry');
        $context = $this->app->make('request.context');

        // Get global middleware from config
        $globalMiddlewares = $this->app->config('app.global_middlewares', []);

        // Get route-specific middleware
        $routeMiddlewares = $this->route->getMiddleware();

        // Merge: global first, then route-specific
        $allMiddlewares = array_merge($globalMiddlewares, $routeMiddlewares);

        // Resolve to singleton instances
        foreach ($allMiddlewares as $middleware) {
            $instance = $registry->resolve($middleware);
            if ($instance) {
                $this->middlewareInstances[] = $instance;
                // Track in context for termination
                $context->addMiddleware($instance);
            }
        }
    }

    protected function runThroughMiddleware()
    {
        return (new Pipeline($this->app))
            ->send($this->request)
            ->through($this->middlewareInstances)
            ->via('handle')
            ->then(function($request) {
                return $this->executeController($request);
            });
    }

    protected function executeController($request)
    {
        $action = $this->route->getAction();

        // Get route parameters from the original WP request
        $routeParams = [];
        if ($this->app->bound('current.wp.request')) {
            $wpRequest = $this->app->make('current.wp.request');
            if ($wpRequest instanceof \WP_REST_Request) {
                // Get URL parameters (like {id})
                $urlParams = $wpRequest->get_url_params();
                if (is_array($urlParams)) {
                    $routeParams = $urlParams;
                }
            }
        }

        // Merge request object with route parameters for dependency injection
        $parameters = array_merge($routeParams, ['request' => $request]);

        if (is_callable($action)) {
            return $this->app->call($action, $parameters);
        }

        if (is_array($action) && count($action) === 2) {
            [$controller, $method] = $action;
            $controllerInstance = $this->app->make($controller);
            return $this->app->call([$controllerInstance, $method], $parameters);
        }

        throw new \Exception('Invalid route action');
    }

    protected function handleException(\Throwable $e)
    {
        // Return error array (Route will convert to WP_Error)
        $statusCode = $e->getCode() ?: 500;

        if ($statusCode < 100 || $statusCode > 599) {
            $statusCode = 500;
        }

        return [
            'error' => true,
            'message' => $e->getMessage(),
            'code' => $statusCode,
            'exception' => get_class($e),
        ];
    }

    public static function create(Application $app, Route $route)
    {
        return new static($app, $route);
    }
}
