<?php


namespace CCDN\Helpers\Http;

use CCDN\Helpers\Exception\CCDNException;
use CCDN\Helpers\Exception\CCDNRuntimeException;
use CCDN\Helpers\Facade\Http\Response;
use CCDN\Helpers\Facade\Http\Request;
use CCDN\Helpers\Facade\Http\Url;

class Router
{
    /**
     * @var array With all routes
     */
    private $routes;

    /**
     * Router constructor.
     */
    public function __construct()
    {
        $this->routes = [];
    }

    /**
     * Set action for _GET request
     *
     * @param string $actionSignature
     * @param string $controller
     * @param string $method
     * @param string $parent
     */
    public function get($actionSignature, $controller, $method, $parent = null)
    {

        $this->routes[$actionSignature] = [
            'controller' => $controller,
            'method' => $method,
            'parent' => $parent,
            'allow_request_method' => 'GET',
        ];
    }

    /**
     * Set action for _POST request
     *
     * @param string $actionSignature
     * @param string $controller
     * @param string $method
     * @param string $parent
     */
    public function post($actionSignature, $controller, $method, $parent = null)
    {

        $this->routes[$actionSignature] = [
            'controller' => $controller,
            'method' => $method,
            'parent' => $parent,
            'allow_request_method' => 'POST',
        ];

    }

    /**
     * Call controller method from _GET param /admin.php?mod=ccdn&action={$actionUrl}
     *
     * @param string $actionUrl
     *
     * @return mixed
     * @throws CCDNException
     */
    public function touch($actionUrl)
    {

        if (!isset($this->routes[$actionUrl])) {
            throw new CCDNException("Action \"{$actionUrl}\" not exists", 404);
        }

        $parent = $this->routes[$actionUrl]['parent'];
        $allow_request_method = $this->routes[$actionUrl]['allow_request_method'];

        $isAllowedSubAction = $this->isAllowedSubAction();
        if ($isAllowedSubAction && $allow_request_method == 'POST') {
            Response::redirect($parent === null ? Url::to() : Url::to($parent));
            return false;
        }

        if (!$this->isMethod($allow_request_method) && !$isAllowedSubAction) {
            $userMethod = $this->getMethod();
            throw new CCDNException("Request method \"{$userMethod}\" not Allowed", 405);
        }

        $method = $this->routes[$actionUrl]['method'];
        $controller = $this->routes[$actionUrl]['controller'];
        return $this->_callControllerAction($controller, $method, $parent);
    }

    /**
     * Check is current REQUEST_METHOD equal $method
     *
     * @param string $method
     *
     * @return bool
     */
    private function isMethod($method = '')
    {
        return $this->getMethod() === $method;
    }

    /**
     * Return current REQUEST_METHOD
     *
     * @return mixed
     */
    private function getMethod()
    {
        return $_SERVER['REQUEST_METHOD'];
    }

    /**
     * Validate default DLE actions
     *
     * @return bool
     */
    private function isAllowedSubAction()
    {
        $allowedActions = [
            'dologin',
        ];

        $subaction = Request::post('subaction');

        if (empty($subaction))
            return false;

        return in_array($subaction, $allowedActions);
    }

    /**
     * Call controller action and return result
     *
     * @param string $controllerClassName - namespace to controller
     * @param string $action - controller method
     * @param string $parent - parent method
     *
     * @return mixed
     */
    private function _callControllerAction($controllerClassName, $action, $parent)
    {
        $controller = ($parent === null ? new $controllerClassName() : new $controllerClassName($parent));

        if (!method_exists($controllerClassName, $action)) {
            throw new CCDNRuntimeException("Method {$action}() in {$controllerClassName}::class not exists");
        }

        return $controller->$action(new \CCDN\Helpers\Http\Request());
    }
}
