<?php

    namespace App\System\Basic;

    use App\System\Vendor\bePlugin;

    class beRouter {
        static $beRoutes = [];
        static $beRouteNames = [];
        static $beLastMethod = "",$beLastPattern = "",$bePrefix = "",$beName = "",$beUserIP = "",$beActiveName = "";
        const bePatterns = [
            "id" => "([0-9]+)",
            "id?" => "([0-9]?)",
            "str" => "([a-zA-Z0-9-_]+)",
            "str?" => "([a-zA-Z0-9-_]?)",
            "all" => "(.*)"
        ];
        public static function beRoute($pattern = "",$module,$method = "get") {
            $pattern = self::$bePrefix.$pattern;
            self::$beRoutes[$method][$pattern] = [
                "module" => $module
            ];
            self::$beLastMethod = $method;
            self::$beLastPattern = $pattern;
            return new self();
        }
        public static function bePrefix($prefix = "",$name = ""){
            self::$bePrefix = $prefix;
            self::$beName = $name;
            return new self();
        }
        public function beMatch($name,$regex){
            self::$beRoutes[self::$beLastMethod][self::$beLastPattern]["regexs"][$name] = $regex;
            return $this;
        }
        public function beData($name,$value){
            self::$beRoutes[self::$beLastMethod][self::$beLastPattern]["data"][$name] = $value;
            return $this;
        }
        public function beSpecial(){
            self::$beRoutes[self::$beLastMethod][self::$beLastPattern]["special"] = 1;
            return $this;
        }
        public function beSetName($name = ""){
            self::$beRouteNames[self::$beName.$name] = self::$beLastPattern;
            self::$beRoutes[self::$beLastMethod][self::$beLastPattern]["name"] = self::$beName.$name;
            return $this;
        }
        public function beMiddleWare($middleware){
            if(is_string($middleware)){
                $middleware = [$middleware];
            }
            self::$beRoutes[self::$beLastMethod][self::$beLastPattern]["middleware"] = $middleware;
            return $this;
        }
        public function beGroup($closure){
            call_user_func($closure);
            self::$bePrefix = "";
            self::$beName = "";
            return $this;
        }
        public static function beGetRoute($name = "",$params = []){
            $key = self::$beRouteNames[$name];
            if(empty($key)){
                return false;
            }
            foreach($params as $name => $value){
                $key = str_replace("{{$name}}",$value,$key);
            }
            return $key;
        }
        public static function beGetMethod(){
            return strtolower($_SERVER["REQUEST_METHOD"]);
        }
        public static function beGetUrl(){
            if(isset($_SERVER["HTTP_CF_CONNECTING_IP"])){
                $ipaddress = $_SERVER["HTTP_CF_CONNECTING_IP"];
            }
            else{
                $ipaddress = $_SERVER["REMOTE_ADDR"];
            }
            self::$beUserIP = $ipaddress;
            return explode("?",$_SERVER["REQUEST_URI"])[0];
        }
        public function __call($name,$arguments){
            if($name === "beName"){
                return call_user_func(array($this,"beSetName"),$arguments[0]);
            }
        }
        public static function __callStatic($name,$arguments){
            if($name === "beName"){
                self::$beName = $arguments[0];
                return new self();
            }
        }
        public static function beRedirect($url = ""){
            header("Location: {$url}");
            exit;
        }
        public static function beFindActiveRoute(){
            $method = self::beGetMethod();
            $url = self::beGetUrl();
            $routes = self::$beRoutes[$method];
            foreach($routes as $pattern => $data){
                if(@$data["regexs"]){
                    foreach($data["regexs"] as $key => $regex){
                        if(@self::bePatterns[$regex]){
                            $pattern = str_replace("{{$key}}",self::bePatterns[$regex],$pattern);
                        }
                        else{
                            $pattern = str_replace("{{$key}}",$regex,$pattern);
                        }
                    }
                }
                if(preg_match("@^{$pattern}$@",$url,$matches)){
                    return $data["name"];
                }
            }
            return false;
        }
        public static function beRun(){
            $method = self::beGetMethod();
            $url = self::beGetUrl();
            $routes = self::$beRoutes[$method];
            $status = false;
            foreach($routes as $pattern => $data){
                if(@$data["regexs"]){
                    foreach($data["regexs"] as $key => $regex){
                        if(@self::bePatterns[$regex]){
                            $pattern = str_replace("{{$key}}",self::bePatterns[$regex],$pattern);
                        }
                        else{
                            $pattern = str_replace("{{$key}}",$regex,$pattern);
                        }
                    }
                }
                if(preg_match("@^{$pattern}$@",$url,$matches)){
                    self::$beActiveName = $data["name"];
                    if(@$data["middleware"]){
                        $middlewares = @$data["middleware"] ?? [];
                        foreach($middlewares as $key => $middleware){
                            $middlewarename = "";
                            if(is_numeric($key)){
                                $middlewarename = $middleware;
                                $middlewaredata = null;
                            }
                            else{
                                $middlewarename = $key;
                                $middlewaredata = $middleware;
                            }
                            $controllerName = "App\System\Middleware\\{$middlewarename}Middleware";
                            $controller = new $controllerName();
                            $controller->handle($middlewaredata);
                        }
                    }
                    array_shift($matches);
                    if(@$data["data"]){
                        foreach($data["data"] as $value){
                            $matches[] = $value;
                        }
                    }
                    bePlugin::beRunHook("router_route_start_pre",["route_name" => $data["name"]]);
                    if(is_callable($data["module"])){
                        $view = call_user_func_array($data["module"],$matches);
                    }
                    else{
                        $classData = explode("@",$data["module"]);
                        if(@!$data["special"]){
                            $controllerName = "App\System\Controller\\{$classData[0]}Controller";
                        }
                        else{
                            $controllerName = "App\System\Plugin\\{$classData[0]}";
                        }
                        $controller = new $controllerName();
                        $view = call_user_func_array([$controller,$classData[1]],$matches);
                    }
                    $view = bePlugin::beRunHook("router_route_start_post",["route_name" => $data["name"],"view" => $view])["view"];
                    $status = $view;
                    break;
                }
            }
            return $status;
        }
    }

?>