<?php

include_once __ROOT_DIR . '/libs/php-jwt/src/BeforeValidException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/ExpiredException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/SignatureInvalidException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/JWT.php';
use \Firebase\JWT\JWT;

class Request
{
    protected $controllerName;
    protected $uriParameters;
    protected $data;
    protected static $_instance;

    public static function getCurrentRequest()
    {
        if (is_null(self::$_instance)) {
            self::$_instance = new Request();
        }
      
        return self::$_instance;
    }

    public function __construct()
    {
        $this->initBaseURI();
        $this->initControllerAndParametersFromURI();
        $this->initData();
    }

    // intialise baseURI
    // e.g. http://eden.imt-lille-douai.fr/~luc.fabresse/api.php => __BASE_URI = /~luc.fabresse
    // e.g. http://localhost/CDAW/api.php => __BASE_URI = /CDAW
    protected function initBaseURI()
    {
        $this->baseURI = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
    }

    // intialise controllerName et uriParameters
    // controllerName contient chaîne 'default' ou le nom du controleur s'il est présent dans l'URI (la requête)
    // uriParameters contient un tableau vide ou un tableau contenant les paramètres passés dans l'URI (la requête)
    // e.g. http://eden.imt-lille-douai.fr/~luc.fabresse/api.php
    //    => controllerName == 'default'
    //       uriParameters == []
    // e.g. http://eden.imt-lille-douai.fr/~luc.fabresse/api.php/user/1
    //    => controllerName == 'user'
    //       uriParameters == [ 1 ]
    protected function initControllerAndParametersFromURI()
    {
        $prefix = $_SERVER['SCRIPT_NAME'];
        $uriParameters = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

        $i=0;
        while ($i<strlen($prefix) && $i<strlen($uriParameters)) {
            if ($prefix[$i]===$uriParameters[$i]) {
                $i++;
            }
        }

        $uriParameters = substr($uriParameters, $i);

        $uriParameters = trim($uriParameters, '/');
        $uriSegments = explode('/', $uriParameters);

        $this->controllerName = array_shift($uriSegments) ?: "default";
        $this->uriParameters = $uriSegments;
    }

    // ==============
    // Public API
    // ==============

    // retourne le name du controleur qui doit traiter la requête courante
    public function getControllerName()
    {
        return $this->controllerName;
    }

    public function getUriParams()
    {
        return $this->uriParameters;
    }

    public function initData()
    {
        if ($this->getHttpMethod() === 'PUT' || $this->getHttpMethod() === 'POST') {
            $jsondata=file_get_contents("php://input");
            $this->data = json_decode($jsondata, true);
        }
    }
   
    // retourne la méthode HTTP utilisée dans la requête courante
    public function getHttpMethod()
    {
        return $_SERVER["REQUEST_METHOD"];
    }

    public function getData()
    {
        return $this->data;
    }
    // Return JWT token (string) in Authorization header or throw an exception
    public function getJwtToken()
    {
        // Field names are case-insensitive : https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
        $headers = array_change_key_case(getallheaders());
        if (!isset($headers['authorization'])) {
            throw new Exception("Missing Authorization field");
        }
        $autorization = $headers['authorization'];
        $arr = explode(" ", $autorization);

        if (count($arr)<2) {
            throw new Exception("Missing JWT token");
        }

        $jwt_token = $arr[1];

        return $jwt_token;
    }

    // Return array with decodedJWT or error message if decoding fails
    public function verifyJwtToken()
    {
        try {
            $jwt_token = $this->getJwtToken();
            $decodedJWT = JWT::decode($jwt_token, JWT_BACKEND_KEY, array('HS256'));
            
            $arrayResult = [
                "message" => "Valid token.",
                "decodedJWT" => $decodedJWT
            ];
        } catch (Exception $e) {
            header('WWW-Authenticate: Bearer realm="'.JWT_ISSUER.'"');
   
            $arrayResult = [
                "message" => "Access denied.",
                "error" => $e->getMessage()
            ];
        }
        return $arrayResult;
    }

    public function getIpAddr()
    { 
        if(!empty($_SERVER['HTTP_CLIENT_IP'])){ 
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        }elseif(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){ 
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; 
        }else{ 
            $ip = $_SERVER['REMOTE_ADDR']; 
        }

        return $ip; 
    } 
}