<?php

namespace WillySoft\Http;

abstract class Route
{
    public static array $groups = [
        // default global group
        []
    ];

    public static function match(string $methods, string $path, callable $callback)
    {
        // check if request methods match 
        if (!in_array($_SERVER['REQUEST_METHOD'],
            array_map(strtoupper(...), explode('|', $methods))
        )) return;

        // check if the route matches and add parameters if any
        // TODO: this is just really messy man wtf
        if (!isset($_SERVER['PATH_INFO'])) {
            $_SERVER['PATH_INFO'] = '/';
        }
        $args = [];
        $path_parts         = explode('/', $path);
        $request_path_parts = explode('/', $_SERVER['PATH_INFO']);
        for ($i=0; $i < count($path_parts); $i++) {
            if (empty($path_parts[$i])) {
                continue;
            }
            if ($path_parts[$i][0] === '$') {
                if (!isset($request_path_parts[$i])) {
                    return;
                }
                if ($path_parts[$i][-1] !== '?' && empty($request_path_parts[$i])) {
                    return;
                }
                if (!empty($request_path_parts[$i])) {
                    $args[] = $request_path_parts[$i];
                }
                $request_path_parts[$i] = $path_parts[$i];
            }
        }
        if (
            implode('/', $path_parts) !== implode('/', $request_path_parts)
        ) return;

        // we have a match! run the middlewares before the callback before we die :)
        foreach (self::$groups as $middlewares) {
            foreach ($middlewares as $middleware) {
                $middleware();
            }
        }
        $callback(...$args);
        die();
    }

    public static function get(string $path, callable $callback)    { self::match('get', $path, $callback); }
    public static function post(string $path, callable $callback)   { self::match('post', $path, $callback); }
    public static function put(string $path, callable $callback)    { self::match('put', $path, $callback); }
    public static function patch(string $path, callable $callback)  { self::match('patch', $path, $callback); }
    public static function delete(string $path, callable $callback) { self::match('delete', $path, $callback); }
    public static function any(string $path, callable $callback)    { self::match('get|post|put|patch|delete', $path, $callback); }

    public static function middleware(callable|array $middlewares)
    {
        if (!is_array($middlewares)) {
            $middlewares = [$middlewares];
        }
        foreach ($middlewares as $middleware) {
            self::$groups[(count(self::$groups) - 1)][] = $middleware;
        }
    }

    public static function group(callable $callback)
    {
        self::$groups[] = [];
        $callback();
        array_pop(self::$groups);
    }
}