<?php

namespace WillySoft;

abstract class Route
{
    static $prefix = '';
    static $groups = [[]];

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

        $request_uri_parts = explode('/', urldecode(
            strtok($_SERVER['REQUEST_URI'], '?')
        ));
        $uri_parts = explode('/', self::$prefix . $uri);
        $callback_args = [];
        for ($i = 0; $i < count($uri_parts); $i++) {
            if ($uri_parts[$i] === '')
                continue;
            if ($uri_parts[$i][0] !== '$')
                continue;
            if (!isset($request_uri_parts[$i]))
                return;
            if (
                $uri_parts[$i][-1] !== '?'
                && $request_uri_parts[$i] === ''
            ) return;
            if ($request_uri_parts[$i] !== '')
                array_push($callback_args, $request_uri_parts[$i]);
            $request_uri_parts[$i] = $uri_parts[$i];
        }
        if (
            implode('/', $uri_parts)
            !== implode('/', $request_uri_parts)
        ) return;

        foreach (self::$groups as $middlewares) {
            foreach ($middlewares as $middleware) {
                $middleware();
            }
        }
        $callback(...$callback_args);
        die();
    }

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

    static function use(callable $middleware)
    {
        array_push(
            self::$groups[array_key_last(self::$groups)],
            $middleware
        );
    }

    static function group(string $prefix, callable $callback)
    {
        if (!str_starts_with(
            $_SERVER['REQUEST_URI'],
            self::$prefix . $prefix
        )) return;
        self::$prefix = self::$prefix . $prefix;
        array_push(self::$groups, []);
        $callback();
        array_pop(self::$groups);
        self::$prefix = rtrim(self::$prefix, $prefix);
    }
}