<?php
namespace Core;

class Router
{
    private
        $routes = [],
        $params = [];

    public function getRoutes()
    {
        return $this->routes;
    }

    public function getParams()
    {
        return $this->params;
    }

    public function add($route, $params = [])
    {
        $route = preg_replace('/\//', '\/', $route);
        $route = preg_replace('/\{([a-z]+)\}/', '(?P<\1>[a-z-]+)', $route);
        $route = preg_replace('/\{([a-z]+):([^\}]+)\}/', '(?P<\1>\2)', $route);
        $route = preg_replace('/\{\?([a-z]+):([^\}]+)\}/', '\?(?P<\1>[a-z]+=\2)', $route);
        $route = '/^'.$route.'$/';

        $this->routes[$route] = $params;
    }

    public function match($url)
    {
        $url = htmlspecialchars($url);
        $url = substr_replace($url, '', 0, 1);

        foreach ($this->routes as $route => $params) {
            if (preg_match($route, $url, $matches)) {
                foreach ($matches as $key => $match) {
                    if (is_string($key)) {
                        $params[$key] = $match;
                    }
                }
                if ($putParams = $this->params = $params) {
                    return true;
                }
            }
        }
        return false;
    }

    public function dispatch($url)
    {
        $url = $this->removeQueryStringVariable($url);
        if ($this->match($url)) {
            $controller = $this->params['controller'];
            $controller = $this->convertToStudlyCaps($controller);
            $controller = $this->getNamespace($controller);

            if (class_exists($controller)) {
                $object = new $controller();

                $action = $this->params['action'];
                $action = $this->convertToCamelCaps($action);

                if (is_callable([$object, $action])) {
                    // Check if there's input to the current page
                    if (Input::exists('post')) {
                        $var = $_POST;
                        // Check the token
                        if (Token::check($var['_token'])) {
                            // Get the method
                            if (isset($var['_method'])) {
                                $action = $var['_method'];
                            }
                        } else {
                            // Token invalid
                            throw new \Exception("Token invalid", 498);
                        }
                        unset($var['_token']);
                        unset($var['_method']);
                    } elseif (Input::exists('get')) {
                        $get_var = $_GET;
                    }
                    if (array_key_exists('id', $this->params)) {
                        $var['id'] = $this->params['id'];
                    } elseif (array_key_exists('status', $this->params)) {
                        $get_var = preg_replace('/^[a-z]+=/', '', $get_var['status']);
                    }
                    if (isset($var)) {
                        return $object->$action($var);
                    } elseif (isset($get_var)) {
                        return $object->$action($get_var);
                    } else {
                        return $object->$action();
                    }
                }
            }
            throw new \Exception("Method not found", 400);
        }
        throw new \Exception("Page not found", 404);
    }

    private function removeQueryStringVariable($url)
    {
        $parts = explode('&', $url);
        return $url = $parts[0];
    }

    private function convertToStudlyCaps($string)
    {
        return str_replace(' ', '', ucwords(str_replace('-', ' ', $string)));
    }

    private function getNamespace($controller)
    {
        return $namespace = 'App\Controllers\\' . $controller;
    }

    private function convertToCamelCaps($string)
    {
        return lcfirst($this->convertToStudlyCaps($string));
    }
}
