<?php

namespace App\Core;

class Router
{
    private array $routes = [];

    public function add(string $method, string $path, array|callable $handler, array $middleware = []): void
    {
        $this->routes[] = [
            'method' => strtoupper($method),
            'path' => rtrim($path, '/') ?: '/',
            'handler' => $handler,
            'middleware' => $middleware,
        ];
    }

    public function get(string $path, array|callable $handler, array $middleware = []): void
    {
        $this->add('GET', $path, $handler, $middleware);
    }

    public function post(string $path, array|callable $handler, array $middleware = []): void
    {
        $this->add('POST', $path, $handler, $middleware);
    }

    public function dispatch(Request $request, Container $container): Response
    {
        if ($request->method() === 'OPTIONS') {
            return Response::json(['success' => true, 'data' => null, 'error' => null]);
        }

        foreach ($this->routes as $route) {
            if ($route['method'] === $request->method() && $route['path'] === $request->path()) {
                $handler = fn (Request $req) => $this->callHandler($route['handler'], $req, $container);

                foreach (array_reverse($route['middleware']) as $middlewareClass) {
                    $next = $handler;
                    $handler = function (Request $req) use ($container, $middlewareClass, $next) {
                        return $container->get($middlewareClass)->handle($req, $next);
                    };
                }

                return $handler($request);
            }
        }

        return \App\Http\Responses\ApiResponse::error('Endpoint not found', 404, [
            'path' => $request->path(),
            'method' => $request->method(),
        ]);
    }

    private function callHandler(array|callable $handler, Request $request, Container $container): Response
    {
        if (is_callable($handler)) {
            return $handler($request);
        }

        [$class, $method] = $handler;
        return $container->get($class)->{$method}($request);
    }
}
