<?php
namespace Qii\Base;

use Qii\Request\Http;

/**
 * Route
 */
class Route
{
    /**
     * group 路由前缀
     * @var string
     */
    public $prefix = '';
    /**
     * 路由 middleware
     * @var array
     */
    public $middleware = [];
    /**
     * 路由
     * @var array
     */
    private $route = [];
    /**
     * 存储转换后的路由和middleware
     *
     * @var array $stored
     */
    private $stored = [];

    public function __construct() {
        $this->clean();
    }

    /**
     * 清理middleware和路由规则
     *
     * @return void
     */
    public function clean() {
        $this->prefix = '';
        $this->middleware = [];
        $this->route = [
            'GET' => [],
            'POST' => [],
            'DELETE' => [],
            'PUT' => [],
            'HEAD' => [],
            'ANY' => []
        ];
    }

    public static function getInstance() {
        return \Qii::getInstance("Qii\Base\Route");
    }

    public function setRoute($route){
        if (!is_array($route) && !in_array($route, $this->route)) {
            $this->route[] = $route;
        }
        $this->route = array_merge($this->route, $route);
    }

    public static function prefix($name) {
        $route = self::getInstance();
        $route->clean();
        $route->prefix = $name;
        return $route;
    }

    /**
     * 设置中间件
     * @param array|string $middleware
     * @return $this
     */
    public function setMiddleware($middleware) {
        if(!is_array($middleware)) {
            $this->middleware[] = $middleware;
        }else{
            $this->middleware = array_merge($this->middleware, $middleware);
        }
        return $this;
    }

    public function gatherMiddleware(){
        return array_unique($this->middleware);
    }

    public function group($callable) {
        $route = \Qii::getInstance("Qii\Base\Route");
        call_user_func($callable, $route);
        $this->stored[] = [$route->middleware, $route->route];
        return $this;
    }

    public function get($uri, $callable){
        $uri = $this->appendPrefix($this->prefix, $uri);
        $this->route['GET'][] = [$uri, $callable];
        return $this;
    }

    public function post($uri, $callable) {
        $uri = $this->appendPrefix($this->prefix, $uri);
        $this->route['POST'][] = [$uri, $callable];
        return $this;
    }

    /**
     * 补充前缀
     * @param string $prefix 前缀
     * @param string $uri uri
     * @return mixed|string
     */
    protected function appendPrefix($prefix, $uri){
        if(!$prefix) {
            return $uri;
        }
        return $prefix . '/'. ltrim($uri, '/');;
    }
    public function put($uri, $callable) {
        $uri = $this->appendPrefix($this->prefix, $uri);
        $this->route['PUT'][] = [$uri, $callable];
        return $this;
    }

    public function delete($uri, $callable) {
        $uri = $this->appendPrefix($this->prefix, $uri);
        $this->route['DELETE'][] = [$uri, $callable];
        return $this;
    }

    public function any($uri, $callable) {
        $uri = $this->appendPrefix($this->prefix, $uri);
        $this->route['ANY'][] = [$uri, $callable];
        return $this;
    }

    /**
     * 匹配路由并执行
     *
     * @param $request
     * @return bool
     */
    public function match(Http $request, $next) {
        $route = $this->getStoredRoute();
        $method = strtoupper($request->getMethod());
        $uri = $request->getRequestUri();
        $middleware = [];
        $callable = '';
        foreach ($route as $item) {
            $middleware = $item[0];
            $subRoute = $item[1];
            if(!isset($subRoute[$method]) && !isset($subRoute['ANY'])) {
                continue;
            }
            $subRoute['ANY'] = isset($subRoute['ANY']) ? (array) $subRoute['ANY'] : array();
            $subRoute[$method] = isset($subRoute[$method]) ? (array) $subRoute[$method] : array();
            $routes = array_merge($subRoute[$method], $subRoute['ANY']);
            $callable = '';

            foreach ($routes as $routeUri) {
                if ($uri == $routeUri[0]) {
                    $callable = $routeUri[1];
                    break;
                }
            }
            if ($callable) {
                break;
            }
        }
        if (!$callable || count($middleware) == 0) {
            return $next($request);
        }
        //命中后，执行相应程序后就不往下执行
        $middleware = array_reverse(array_unique($middleware));
        $result = array_reduce($middleware, function ($carry, $item){
            return function () use ($carry, $item){
                return _loadClass($item)->handle(\Qii::getInstance()->request, $carry);
            };
        }, function(){
            return true;
        })();
        if (!$result) return false;
        if (!$this->make($callable)){
            return $next($request);
        }
        return false;
    }

    /**
     * 执行 $callable
     * @param mix $callable 执行方法
     * @return bool
     */
    public function make($callable) {
        switch ($callable) {
            case ($callable instanceof  \Closure):
                echo call_user_func($callable);
                break;
            case is_array($callable):
                $action = (isset($callable[1]) ? $callable[1] : "index"). 'Action';
                _loadClass($callable[0])->$action();
                break;
            case gettype($callable) == 'string':
                _loadClass($callable)->indexAction();
                break;
        }
        if ($callable) {
            return true;
        }
        return false;
    }

    /**
     * 获取所有设置的路由
     *
     * @return mixed
     */
    public function getStoredRoute(){
        return self::getInstance()->stored;
    }
}