<?php
require_once realpath(__DIR__."/../lib/php-jwt/vendor/autoload.php");

use Firebase\JWT\JWT;

class Auth {
    public $privateKey = 'wscO4QaF'; // Key de codificación
    public $expire = 3600; // 3600 Expire time in seconds
    public $renewTime = 1200; // 1200 Renew time before expired in seconds
    public $now;
    /**
     * @param privateKey: Private Key
     */
    public function __construct($privateKey = null) {
        if ($privateKey) $this->privateKey = $privateKey;
        $this->now = time();
    }

    static function AuthenticateUserLocal($loginAccess){
        global $TABLE_PREFIX;
        $user = $loginAccess[0];
        $pass = $loginAccess[1];

        $userBD = mysql_query_fetch_all_assoc("SELECT *,(neverExpires = '0' AND expiresDate < NOW()) as isExpired FROM ".$TABLE_PREFIX."accounts WHERE `username`='".$user."' and `password`= '".md5($pass)."' LIMIT 1");
        $userBD = @$userBD[0];
        return $userBD;
    }

    static function AuthenticateUser($loginAccess){
        global $TABLE_PREFIX;
        if (count($loginAccess)<2) API::error(new ApiError("Las credenciales son incorrectas"));
        $user = $loginAccess[0];
        $pass = $loginAccess[1];
        $curl = curl_init();
        
        curl_setopt_array($curl, array(
            CURLOPT_URL => "https://ws.cocosolution.com/api/auth/",
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => "POST",
            CURLOPT_POSTFIELDS => "",
            CURLOPT_HTTPHEADER => array(
                "Accept: */*",
                "Accept-Encoding: gzip, deflate",
                "Authorization: SimpleAuth ".base64_encode($user.":".$pass),
                "Cache-Control: no-cache",
                "Connection: keep-alive",
                "Content-length: 0",
                "Content-type: application/json",
                "Referer: ".$_SERVER["HTTP_HOST"]
            ),
        ));

        $response = curl_exec($curl);
        $err = curl_error($curl);
        
        curl_close($curl);

        if ($err) {
            API::error(new Exception("Login failed"));
        } else if (@json_decode($response,true)["error"]){
            API::error(new Exception("Login failed"));
        }else{
            $schema = loadINI(__DIR__."/../../custom-schema.ini.php");
            if (!@$schema["enabled"]) API::error(new Exception("Login failed"));
            
            try{
                $resultData = json_decode($response,true);
                self::validateUserHash($resultData["data"]["userNum"]);
                return ["num" => $resultData["data"]["userNum"]];
            }catch(Exception $e){
                API::error(new ApiError('Login Failed '.$e->getMessage(),403));
            }
        }
    }

    static function validateUserHash($num){
        $schema = loadINI(__DIR__."/../../custom-schema.ini.php");
        if (!@$schema["enabled"]) API::error(new Exception("Login failed"));
        if(@$schema['config']["hash"]) {
            $allowed_users = explode(',', $schema['config']['hash']);
            if (!in_array(sha1($num), $allowed_users)) API::error(new Exception("Login failed"));
        } else {
            API::error(new Exception("Login failed"));
        }
        // if (@$schema["config"]["hash"] != sha1($num)) API::error(new Exception("Login failed"));
    }

    static function updateTokenUserData(){
        $api = new API();
        $auth = new self();
        $token = array(
            'iat' => $auth->now, // Tiempo que inició el token
            'exp' => $auth->now+($auth->expire), // Tiempo que expirará el token 
            'data' => API::$user
        );
        $jwt = JWT::encode($token, $auth->privateKey);

        API::setToken(["renewToken" => $jwt]);
    }
    static function validateMasterKey($requestToken){
        $schema = loadINI(__DIR__."/../../custom-schema.ini.php");
        if (!@$schema["enabled"]) API::error(new Exception("Login failed"));
        if (@$schema["config"]["masterKey"] != $requestToken) return false;
        return true;
    }
    static function authorizeApi($auth = false) {
        
        $api = new API();
        $auth = new self();
        $requestToken = self::getBearerToken();
        $loginAccess = self::getLoginAccess();
        
        $tokenData = [];

        if (!$requestToken && !$loginAccess) API::error(new ApiError('No token was sent',403));

        if ($requestToken) {
            if (self::validateMasterKey($requestToken)) return ["user" => true];
            try{
                $data = (object)JWT::decode($requestToken, $auth->privateKey, array('HS256'));
                $data->data = (array) $data->data;
                
                API::$user = json_decode(json_encode($data->data), true);
                
                self::validateUserHash(API::$user["num"]);
                
                $difference = $data->exp-$auth->now;
                if ($difference<0){
                    API::error(new ApiError('Token expired',403));
                }else if($difference >= 0 && $difference < $auth->renewTime){
                    $token = array(
                        'iat' => $auth->now, // Tiempo que inició el token
                        'exp' => $auth->now+($auth->expire), // Tiempo que expirará el token 
                        'data' => $data->data
                    );
                    $jwt = JWT::encode($token, $auth->privateKey);
                    // AQUI FALTA CONVALIDAR LOS DATOS DEL USUARIO DEL TOKEN CON LA BBDD PARA 
                    // ECHARLO FUERA SI LOS ACCESOS O ALGUN OTRO DATO HA CAMBIADO
                    $tokenData = ["renewToken" => $jwt,"user" => $data->data,"difference" => ($data->exp-$auth->now)];
                    if ($auth) $tokenData["token"] = $jwt;
                    API::addResponseData($tokenData);
                    
                    return $tokenData;
                }else{
                    $tokenData = ["user" => $data->data,"difference" => ($data->exp-$auth->now)];
                    if ($auth) $tokenData["token"] = $requestToken;
                    API::addResponseData($tokenData);
                    return $tokenData;
                }


            }catch (Exception $e) {
                API::error(new ApiError('Token expired',403));
            }

        }else if ($loginAccess){

            try{
                $authenticated = self::AuthenticateUser($loginAccess);

                if ($authenticated){

                    $token = array(
                        'iat' => $auth->now, // Tiempo que inició el token
                        'exp' => $auth->now+($auth->expire), // Tiempo que expirará el token 
                        'data' => $authenticated
                    );

                    $jwt = JWT::encode($token, $auth->privateKey);    

                    $tokenData = ["token" => $jwt,"expire" => $auth->now+($auth->expire),"user" => ["num" => $authenticated["num"]],"login" => true];

                    API::$user = $authenticated;

                    return $tokenData;
                }else{
                    API::error(new ApiError('Login Failed',403));
                }
            }catch (Exception $e) {
                API::error(new ApiError('Login Failed',403));
            }
        }else{
            API::error(new ApiError('Login Failed',403));
        }

    }

    static function getAuthorizationHeader(){
        $headers = null;
        if (isset($_SERVER['Authorization'])) {
            $headers = trim($_SERVER["Authorization"]);
        }
        else if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI
            $headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
        } elseif (function_exists('apache_request_headers')) {
            $requestHeaders = apache_request_headers();
            // Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
            $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
            //print_r($requestHeaders);
            if (isset($requestHeaders['Authorization'])) {
                $headers = trim($requestHeaders['Authorization']);
            }
        }
        return $headers;
    }

    static function getBearerToken() {
        $headers = self::getAuthorizationHeader();
        if (!empty($headers)) {
            if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
                return $matches[1];
            }
        }
        return null;
    }

    static function getLoginAccess() {
        $headers = self::getAuthorizationHeader();
        if (!empty($headers)) {
            if (preg_match('/Login\s(\S+)/', $headers, $matches)) {
                
                $result = base64_decode($matches[1]);
                if (!$result) API::error(new ApiError("Invalid Login"));
                return explode(":",$result);
            }
        }
        return null;
    }

}