<?php

namespace Snaju\Inception\View;

use Snaju\Inception\Http\Middleware\MiddlewareRegistry;
use Snaju\Inception\Http\Request\WebRequest;
use Snaju\Inception\Http\Response\Response;
use Snaju\Inception\InceptionCore;
use Snaju\Inception\Route\Loaders\Twig\TemplateManager;

/**
 * Class ViewController
 * @package Snaju\Inception\View
 * @method get(\Closure $closure, array $middleware = []): ViewController Get Request
 * @method post(\Closure $closure, array $middleware = []): ViewController Post Request
 * @method getParam(string $token, \Closure $closure, array $middleware = []): ViewController Get Request from URI GET Param
 * @method form(string $token, \Closure $closure, array $middleware = []): ViewController POST Request from POST Param
 */
class ViewController
{

    private static ?ViewController $instance = null;

    private MiddlewareRegistry $middlewareRegistry;

    private WebRequest $request;

    private bool $break = false;

    /**
     * ViewController constructor.
     */
    public function __construct()
    {
        $this->request = InceptionCore::getRequest();
        $this->middlewareRegistry = InceptionCore::$middleware;
    }

    /**
     * @param $name
     * @param $arguments
     * @return ViewController $this
     */
    public function __call($name, $arguments): ViewController
    {
        if (!$this->break) {
            if ($arguments[0] instanceof \Closure) {
                // Is a get/post.

                if (strtoupper($this->request->getMethod()) == strtoupper($name)) {
                    // Is the method we're calling.
                    $this->call($arguments[0], ((isset($arguments[1]) && is_array($arguments[1])) ? $arguments[1] : []));
                }

            } else if (is_string($arguments[0])) {
                // Is a custom get/post for a form.

                if (strtolower($name) == "getparam") {
                    // Get Request
                    if (strtoupper($this->request->getMethod()) == "GET") {
                        // Is a get request
                        if (isset($_GET[$arguments[0]])) {
                            // Contains the argument we're looking for.
                            $this->call($arguments[1], ((isset($arguments[2]) && is_array($arguments[2])) ? $arguments[2] : []));
                        }
                    }
                } else if (strtolower($name) == "form") {
                    // POST Request
                    if (strtoupper($this->request->getMethod()) == "POST") {
                        // Is a POST Request
                        if (isset($_POST[$arguments[0]])) {
                            // Has the token we're looking for.
                            $this->call($arguments[1], ((isset($arguments[2]) && is_array($arguments[2])) ? $arguments[2] : []));
                        }
                    }
                }

            }
        }
        return $this;
    }

    private function call(\Closure $call, $middleware = [])
    {
        $this->middlewareRegistry->init($middleware)->process($this->request, function (WebRequest $request) use ($call) {
            $p = call_user_func($call, $request);
            if (is_bool($p)) {
                $this->break = !$p;
            } else if (is_array($p) || is_object($p)) {
                TemplateManager::merge($p);
            } else if ($p instanceof Response) {
                // Is a response
                $p->sendHeaders();
                $p->sendCookies();
                $p->sendContent();
                exit;
            }

            return $request;
        });
    }

    public function fallback(\Closure $run, $middleware = [])
    {
        $this->call($run, $middleware);
    }

    public function verify($middleware = [])
    {
        $this->middlewareRegistry->init($middleware)->process($this->request, function (WebRequest $request) {
            // Do Nothing.
        });
    }

    public static function getInstance(): ViewController
    {
        if (self::$instance == null) {
            self::$instance = new ViewController();
        }

        return self::$instance;
    }

}

?>