<?php
declare(strict_types=1);

namespace App\Core;

use ReflectionMethod;

final class Router
{
    public function __construct(private readonly array $routes)
    {
    }

    public function dispatch(Request $request): mixed
    {
        if (! preg_match('/^[a-zA-Z0-9\/_-]*$/', $request->path) || str_contains($request->path, '..')) {
            abort(404, 'Rute tidak valid.');
        }

        foreach ($this->routes as [$method, $path, $handler]) {
            if ($request->method === $method && $request->path === $path) {
                if (is_array($handler) && is_string($handler[0]) && is_string($handler[1])) {
                    $controller = new $handler[0]();
                    $callable = [$controller, $handler[1]];

                    return $this->invoke($callable, $request);
                }
            }
        }

        abort(404, 'Halaman tidak ditemukan.');
    }

    private function invoke(callable $callable, Request $request): mixed
    {
        $reflection = new ReflectionMethod($callable[0], $callable[1]);
        $arguments = [];

        foreach ($reflection->getParameters() as $parameter) {
            if ($parameter->getType() && $parameter->getType()->getName() === Request::class) {
                $arguments[] = $request;
            }
        }

        return $callable(...$arguments);
    }
}
