<?php

header("Access-Control-Allow-Origin: *");
require_once("class.dbutils.php");
require_once("class.utils.php");

/////
class RestFrameWork
{
    ////
    public $dbutils;
    public $utils;
    /////
    public function __construct()
    {
        $this->dbutils = new DBUtils();
        $this->utils = new Utils();
        if (!$this->dbutils->isDBInService()) {
            die($this->Response(["message" => "Failed to connect to the database, please try again laiter", "success" => false], 500));
        }
    }

    public function decodeHeaders()
    {
        $headers = array();
        foreach (getallheaders() as $name => $value) {
            $headers[$name] = $value;
        }
        return $headers;
    }

    public function execPostRequest($url, $data, $headers = array())
    {
        $requestHeaders = array('Content-Type: application/json', 'Content-Length: ' . strlen($data));
        for ($i = 0; $i < count($headers); $i++) {
            array_push($requestHeaders, $headers[$i]);
        }
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        //execute post
        $result = curl_exec($ch);
        //close connection
        curl_close($ch);
        $jsonResult = json_decode($result, true);
        return  $jsonResult;
    }

    public function execGetRequest($url, $data, $headers = array())
    {
        $requestHeaders = array('Content-Type: application/json', 'Content-Length: ' . strlen($data));
        for ($i = 0; $i < count($headers); $i++) {
            array_push($requestHeaders, $headers[$i]);
        }
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        //execute post
        $result = curl_exec($ch);
        //close connection
        curl_close($ch);
        $jsonResult = json_decode($result, true);
        return  $jsonResult;
    }

    public function execUploadRequest($url, $params, $filePath, $type, $fileName, $newheaders)
    {
        $ch = curl_init();
        $headers =  array_merge(array('Content-Type: multipart/form-data', 'Content-Type: application/json'), $newheaders);
        $data = array_merge(array($params["upload_name"] => curl_file_create($filePath, $type, $fileName)), $params);
        //start curl request
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        $response = curl_exec($ch);
        curl_close($ch);
        $jsonResult = json_decode($response, true);
        return $response;
    }

    public function get($request)
    {
        // var_dump($_GET[$request]);
        $RES = trim($_GET[$request]);
        return $RES;
    }

    public function getUserIp()
    {
        return $_SERVER['REMOTE_ADDR'];
    }

    public function post($request)
    {
        $RES = trim($_POST[$request]);
        return $RES;
    }



    public function clean($data)
    {
        return htmlspecialchars(strip_tags(trim($data)));
    }

    public function getHostURL()
    {
        //$protol = $_SERVER['HTTPS'] ? "https://" : "http://";
        $url = "http://" . $_SERVER['HTTP_HOST'] . "/";
        return $url;
    }



    public function getLangCode($headers)
    {
        $langPresent = !empty($headers["lang"]) ? true : false;
        if ($langPresent) {
            return   htmlspecialchars(strip_tags(trim($headers["lang"])));
        } else {
            return "en";
        }
    }


    public function redirect($link)
    {
        header("Location:$link");
    }

    public function allow($method, $response = null)
    {
        $REQUEST_METHOD = $_SERVER["REQUEST_METHOD"];
        if ($REQUEST_METHOD !==  strtoupper($method)) {
            die($this->Response(["message" => "Invalid request method", "success" => false], 400));
        }
    }

    public function UserNameExistsById($username, $userid)
    {
        /////////////////////
        $userid = intval($userid);
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE id != :uuserid AND username=:uusername");
        $stmt->bindparam(":uusername", $username);
        $stmt->bindparam(":uuserid", $userid);
        if ($stmt->execute()) {
            if ($stmt->rowCount() > 0) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public function EmailExistsById($email, $userid)
    {
        $userid = intval($userid);
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE id != :uuserid AND email=:uemail");
        $stmt->bindparam(":uemail", $email);
        $stmt->bindparam(":uuserid", $userid);
        if ($stmt->execute()) {
            if ($stmt->rowCount() > 0) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public function UserIdById($userid)
    {
        $userid = intval($userid);
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE id = :uuserid");
        $stmt->bindparam(":uuserid", $userid);
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            return true;
        } else {
            return false;
        }
    }

    public function UserExists($username)
    {
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE username=:uusername");
        $stmt->bindparam(":uusername", $username);
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            return true;
        } else {
            return false;
        }
    }

    public function EmailExists($email)
    {
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE email=:uemail");
        $stmt->bindparam(":uemail", $email);
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            return true;
        } else {
            return false;
        }
    }







    public function UserExistsByCompanyId($username, $companyid)
    {
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE username=:uusername AND company=:ucompanyid");
        $stmt->bindparam(":uusername", $username);
        $stmt->bindparam(":ucompanyid", $companyid);
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            return true;
        } else {
            return false;
        }
    }

    public function EmailExistsByCompanyId($email, $companyid)
    {
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE email=:uemail AND company=:ucompanyid");
        $stmt->bindparam(":uemail", $email);
        $stmt->bindparam(":ucompanyid", $companyid);
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            return true;
        } else {
            return false;
        }
    }


    public function getUser($userid)
    {
        $response = array();
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE id = :uuserid OR user_no = :uuserid");
        $stmt->bindparam(":uuserid", $userid);
        $stmt->execute();
        $counter = $stmt->rowCount();
        if ($counter > 0) {
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
        } else {
            return array("message" => "User doesn't exist", "success" => true);
        }
        $response = $row;
        $userid = $row["id"];
        $companyid = $response["company"];
        /////////////////////////////////
        if (!$this->UserHasToken($userid)) {
            // create token
            $this->createToken($userid, $companyid);
        }
        ////////////////
        $response["token"] = $this->getUserToken($userid);
        $response["success"] = true;
        return $response;
    }

    public function purge($key)
    {
        return isset($_REQUEST[$key]);
    }

    public function request($key)
    {
        return $_REQUEST[$key];
    }

    public function getUserByUsername($username, $companyid)
    {
        $response = new StdClass;
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE company=:ucompanyid AND (username=:uusername OR email=:uusername)");
        $stmt->bindparam(":uusername", $username);
        $stmt->bindparam(":ucompanyid", $companyid);
        $stmt->execute();
        $counter = $stmt->rowCount();
        ////////////////////////////////////
        if ($counter == 1) {
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $response = $row;
            $userid = $response["id"];
            $companyid = $response["company"];
            ////////////////
            $stmt2 = $this->dbutils->runQuery("SELECT * FROM api_userprofile WHERE user_id=:uuserid");
            $stmt2->bindparam(":uuserid", $userid);
            $stmt2->execute();
            $row2 = $stmt2->fetch(PDO::FETCH_ASSOC);
            $response["user_profile"] = $row2;
            if (!$this->UserHasToken($userid)) {
                // create token
                $this->createToken($userid, $companyid);
            }
            $response["token"] = $this->getUserToken($userid);
            $response["success"] = true;
        } else {
            die($this->Response(["message" => "Username or email doesn't exist", "success" => false], 400));
        }
        return $response;
    }

    public function authCreate($fields, $companyid)
    {
        extract($fields);
        $username = trim($username);
        if (!empty($username) && $this->UserExists($username)) {
            die($this->Response(["message" => "Username already taken", "success" => false], 400));
        } else if (!$this->utils->isValidEmail($email)) {
            die($this->Response(["message" => "Invalid Email address", "success" => false], 400));
        } else if ($this->EmailExists($email)) {
            die($this->Response(["message" => "Email already taken", "success" => false], 400));
        } else {
            $stmt2 = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE email=:uemail");
            $stmt2->bindparam(":uemail", $email);
            $stmt2->execute();
            if ($stmt2->rowCount() > 0) {
                die($this->Response(["message" => "Email already taken", "success" => false], 400));
            } else {
                $newpassword = $this->utils->passwordEncrypt($password, 'md5');
                $verif_token = $this->utils->getRandom();
                $userno = $this->utils->getRandom();
                $user_name = empty($username) ? $first_name . $last_name . $userno : $username;
                /// run and insert query
                $stmt3 = $this->dbutils->runQuery("
                        INSERT INTO pm_user SET
                        company = :ucompany,
                        user_no = :uuserno,
                        type = :utype,
                        username = :uusername,
                        first_name = :ufname,
                        last_name = :usname,
                        email = :uemail,
                        password = 	:upass,
                        verif_token = :uveriftoken,
                        is_verified = :uisverified,
                        is_active = :uisactive,
                        is_staff = :uisstaff,
                        is_super_user = :uissuperuser,
                        last_login = NOW(),
                        last_updated = NOW()");
                $stmt3->bindParam(":ucompany", $companyid);
                $stmt3->bindParam(":uuserno", $userno);
                $stmt3->bindParam(":uusername", $user_name);
                $stmt3->bindParam(":utype", $type);
                $stmt3->bindParam(":ufname", $first_name);
                $stmt3->bindParam(":usname", $last_name);
                $stmt3->bindParam(":uemail", $email);
                $stmt3->bindParam(":upass", $newpassword);
                $stmt3->bindParam(":uveriftoken", $verif_token);
                $stmt3->bindParam(":uisverified", $is_verified);
                $stmt3->bindParam(":uisstaff", $is_staff);
                $stmt3->bindParam(":uissuperuser", $is_superuser);
                $stmt3->bindParam(":uisactive", $is_active);
                if ($stmt3->execute()) {
                    $last_inserted_id = $this->dbutils->conn->lastInsertId();
                    $user =  $this->getUser($last_inserted_id);
                    if ($user["token"] == null) {
                        $this->createToken($last_inserted_id, $companyid);
                        return $this->getUser($last_inserted_id);
                    } else {
                        return $this->getUser($last_inserted_id);
                    }
                } else {
                    die($this->Response(["message" => "Something went wrong, please try again laiter", "success" => false], 400));
                }
            }
        }
    }

    public function authUpdatePassword($userid, $password)
    {
        $newpassword = $this->utils->passwordEncrypt($password, 'md5');
        ///////////////////////////////////
        $stmt3 = $this->dbutils->runQuery("
        UPDATE pm_user SET
        password = :upassword WHERE id=:uuserid");
        $stmt3->bindParam(":upassword", $newpassword);
        $stmt3->bindParam(":uuserid", $userid);
        if ($stmt3->execute()) {
            return true;
        } else {
            die($this->Response(["message" => "Something went wrong, please try again laiter", "success" => false], 400));
        }
    }
    // $verif_token = $data["verif_token"];
    // $is_verified = $data["is_verified"];

    public function updateUserVerificationToken($userid, $token = null)
    {
        if (!$token) {
            $verif_token = $this->utils->getRandom();
        } else {
            $verif_token = $token;
        }
        ///////////////////////////////////
        $stmt3 = $this->dbutils->runQuery("
        UPDATE pm_user SET
        verif_token = :uveriftoken, is_verified=false WHERE id=:uuserid");
        $stmt3->bindParam(":uveriftoken", $verif_token);
        $stmt3->bindParam(":uuserid", $userid);
        if ($stmt3->execute()) {
            return true;
        } else {
            die($this->Response(["message" => "Something went wrong, please try again laiter", "success" => false], 400));
        }
    }

    public function VerifyUser($userid, $token = null)
    {
        if (!$token) {
            $verif_token = $this->utils->getRandom();
        } else {
            $verif_token = $token;
        }
        ///////////////////////////////////
        $stmt3 = $this->dbutils->runQuery("SELECT pm_user WHERE id=:uuserid AND verif_token = :uveriftoken");
        $stmt3->bindParam(":uveriftoken", $verif_token);
        $stmt3->bindParam(":uuserid", $userid);
        if ($stmt3->execute()) {
            if ($stmt3->rowCount() > 0) {
                /// update user verification status
                $stmt4 = $this->dbutils->runQuery("UPDATE pm_user SET is_verified=true WHERE id=:uuserid");
                $stmt4->bindParam(":uuserid", $userid);
                if ($stmt4->execute()) {
                    return true;
                } else {
                    die($this->Response(["message" => "Something went wrong, please try again laiter", "success" => false], 400));
                }
                //////////////////////////////////////////////
                return true;
            } else {
                return false;
            }
        } else {
            die($this->Response(["message" => "Something went wrong, please try again laiter", "success" => false], 400));
        }
    }


    public function UserExistsIdByNo($uuserno)
    {
        $uuserno = intval($uuserno);
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE user_no = :uuserno");
        $stmt->bindparam(":uuserno", $uuserno);
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            return true;
        } else {
            return false;
        }
    }


    public function authUpdate($data, $userid)
    {
        ///////////////////////////////
        extract($data);
        //////////////////////////////
        ///////////////////////////////////////////////////////////////////////////
        $old_user = $this->getUser($userid);
        $userid = $old_user["id"];
        ////////////////////////////////
        if (!empty($username) && $this->UserNameExistsById($username, $userid)) {
            return array("message" => "Username already taken", "success" => false);
        } else if (!empty($email) && !$this->utils->isValidEmail($email)) {
            return array("message" => "Invalid Email address", "success" => false);
        } else if (!empty($email) && $this->EmailExistsById($email, $userid)) {
            return array("message" => "Email already taken", "success" => false);
        } else {
            $username = !isset($data["username"]) || empty($data["username"]) ? $old_user["username"] : $username;
            $first_name = !isset($data["first_name"]) || empty($data["first_name"]) ? $old_user["first_name"] : $first_name;
            $last_name = !isset($data["last_name"]) || empty($data["last_name"]) ? $old_user["last_name"] : $last_name;
            $email = !isset($data["email"]) ||  empty($data["email"]) ? $old_user["email"] : $email;
            $newpassword = !isset($data["password"]) ||  empty($data["password"]) ? $old_user["password"] : $this->utils->passwordEncrypt($data["password"], 'md5');
            //////////////////////////////////
            $stmt2 = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE id=:uuserid OR user_no = :uuserid");
            $stmt2->bindparam(":uuserid", $userid);
            if ($stmt2->execute()) {
                if ($stmt2->rowCount() ==  0) {
                    return array("message" => "User with ID doesn't exist", "success" => false);
                } else {
                    /// run and insert query
                    $stmt3 = $this->dbutils->runQuery("UPDATE pm_user SET 
                        username = :uusername,
                        first_name = :ufname,
                        last_name = :usname,
                        email = :uemail,
                        `password` = :upass,
                        last_updated = NOW() WHERE id = :uuserid or user_no=:uuserid");
                    $stmt3->bindParam(":uusername", $username);
                    $stmt3->bindParam(":ufname", $first_name);
                    $stmt3->bindParam(":usname", $last_name);
                    $stmt3->bindParam(":uemail", $email);
                    $stmt3->bindParam(":upass", $newpassword);
                    $stmt3->bindParam(":uuserid", $userid);
                    if ($stmt3->execute()) {
                        $response = $this->getUser($userid);
                        $response["message"] = "";
                        $response["success"] = true;
                        return $response;
                    } else {
                        return array("message" => "Something went wrong, please try again laiter", "success" => false);
                    }
                }
            } else {
                return array("message" => "Something went wrong, please try again laiter", "success" => false);
            }
        }
    }



    public function authUpdateByUserNo($data, $user)
    {
        ///////////////////////////////
        extract($data);
        //////////////////////////////
        if (!empty($username) && $this->UserNameExistsById($username, $userid)) {
            return array("message" => "Username already taken", "success" => false);
        } else if (!empty($email) && !$this->utils->isValidEmail($email)) {
            return array("message" => "Invalid Email address", "success" => false);
        } else if (!empty($email) && $this->EmailExistsById($email, $userid)) {
            return array("message" => "Email already taken", "success" => false);
        } else {
            ///////////////////////////////////////////////////////////////////////////
            $old_user = $this->getUser($userid);
            ////////////////////////////////
            $username = empty($data["username"]) ? $old_user["username"] : $username;
            $first_name = empty($data["first_name"]) ? $old_user["first_name"] : $first_name;
            $last_name = empty($data["last_name"]) ? $old_user["last_name"] : $last_name;
            $email = empty($data["email"]) ? $old_user["email"] : $email;
            $newpassword = empty($data["password"]) ? $old_user["password"] : $this->utils->passwordEncrypt($data["password"], 'md5');
            //////////////////////////////////
            $stmt2 = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE id=:uuserid");
            $stmt2->bindparam(":uuserid", $userid);
            if ($stmt2->execute()) {
                if ($stmt2->rowCount() ==  0) {
                    return array("message" => "User with ID doesn't exist", "success" => false);
                } else {
                    /// run and insert query
                    $stmt3 = $this->dbutils->runQuery("UPDATE pm_user SET 
                        username = :uusername,
                        first_name = :ufname,
                        last_name = :usname,
                        email = :uemail,
                        password = 	:upass,
                        last_updated = NOW() WHERE id = :uuserid");
                    $stmt3->bindParam(":uusername", $username);
                    $stmt3->bindParam(":ufname", $first_name);
                    $stmt3->bindParam(":usname", $last_name);
                    $stmt3->bindParam(":uemail", $email);
                    $stmt3->bindParam(":upass", $newpassword);
                    $stmt3->bindParam(":uuserid", $userid);
                    if ($stmt3->execute()) {
                        $response = $this->getUser($userid);
                        $response["message"] = "";
                        $response["success"] = true;
                        return $response;
                    } else {
                        return array("message" => "Something went wrong, please try again laiter", "success" => false);
                    }
                }
            } else {
                return array("message" => "Something went wrong, please try again laiter", "success" => false);
            }
        }
    }

    public function authenticateLogin($username, $password)
    {
        $password = $this->utils->passwordEncrypt($password, 'md5');
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE (username=:uusername OR email=:uusername)  AND `password`=:upassword");
        $stmt->bindparam(":uusername", $username);
        $stmt->bindparam(":upassword", $password);
        $stmt->execute();
        if ($stmt->rowCount()  == 1) {
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $userid = $row["id"];
            $companyid = $row["company"];
            if (!$this->UserHasToken($userid)) {
                // create token
                $this->createToken($userid, $companyid);
            }
            // login success
            // update lat login status
            $stmt4 = $this->dbutils->runQuery("UPDATE pm_user SET
           last_login = NOW() WHERE id=:uuserid");
            $stmt4->bindParam(":uuserid", $userid);
            $stmt4->execute();
            //// return user
            $user = $this->getUser($userid);
            $user["success"] = true;
            return $user;
        } else {
            return array("message" => "Invalid login credentials", "success" => false);
        }
    }


    public function authenticateLoginUser($username, $password, $companyid)
    {
        $password = $this->utils->passwordEncrypt($password, 'md5');
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user WHERE (username=:uusername OR email=:uusername) AND `password`=:upassword AND company=:ucompanyid");
        $stmt->bindparam(":uusername", $username);
        $stmt->bindparam(":upassword", $password);
        $stmt->bindparam(":ucompanyid", $companyid);
        $stmt->execute();
        if ($stmt->rowCount()  == 1) {
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $userid = $row["id"];
            $companyid = $row["company"];
            if (!$this->UserHasToken($userid)) {
                // create token
                $this->createToken($userid, $companyid);
            }
            // login success
            // update lat login status
            $stmt4 = $this->dbutils->runQuery("UPDATE pm_user SET
           last_login = NOW() WHERE id=:uuserid");
            $stmt4->bindParam(":uuserid", $userid);
            $stmt4->execute();
            //// return user
            $user = $this->getUser($userid);
            $user["success"] = true;
            return $user;
        } else {
            return array("message" => "Invalid login credentials", "success" => false);
        }
    }

    public function createToken($userid, $companyid, $expiry_date = null, $is_active = true)
    {
        if (!$this->UserHasValidToken($userid)) {
            // Disable all aactive user tokens
            $this->DisableAllUserToken($userid);
            // create a new one
            $timestamp = date('Y-m-d H:i:s', time()); //token expirely date
            $token =  str_replace("=", "", $this->utils->encrypt($companyid . "&" . $userid . "&" . $timestamp));
            if ($expiry_date) {
                $expires = true;
            } else {
                $expires = false;
            }
            $stmt3 = $this->dbutils->runQuery(
                "INSERT INTO pm_user_token SET
            user_id = :uuserid,
            token =  :utoken,
            token_generated=:utokengenerated, 
            expiry_date=:uexpirydate,
            expires = :uexpires,
            is_active=:uisactive"
            );
            $stmt3->bindParam(":uuserid", $userid);
            $stmt3->bindParam(":utoken", $token);
            $stmt3->bindParam(":utokengenerated", $timestamp);
            $stmt3->bindParam(":uexpires", $expires);
            $stmt3->bindParam(":uexpirydate", $expiry_date);
            $stmt3->bindParam(":uisactive", $is_active);
            $stmt3->execute();
        } else {
            return array("message" => "User already has a valid token", "success" => false);
        }
    }

    public function getUserToken($userid)
    {
        $response = new StdClass;
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user_token WHERE user_id=:uuserid");
        $stmt->bindparam(":uuserid", $userid);
        $stmt->execute();
        if ($stmt->rowCount() == 1) {
            $response = $stmt->fetch(PDO::FETCH_ASSOC);
        } else {
            return null;
        }
        return $response;
    }

    public function getUserTokenById($tokenid)
    {
        $response = new StdClass;
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user_token WHERE id=:utokenid");
        $stmt->bindparam(":utokenid", $tokenid);
        $stmt->execute();
        if ($stmt->rowCount() == 1) {
            $response = $stmt->fetch(PDO::FETCH_ASSOC);
        } else {
            return null;
        }
        return $response;
    }

    public function getUserByToken($token)
    {
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user_token WHERE token=:utoken");
        $stmt->bindparam(":utoken", $token);
        $stmt->execute();
        $counter = $stmt->rowCount();
        if ($counter == 1) {
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $user_id = $row["user_id"];
            return $this->getUser($user_id);
        } else {
            die($this->Response(["message" => "Authorization token doesn't exists", "success" => false], 400));
        }
    }

    public function getTokenData($token)
    {
        return $this->AuthToken($token);
    }

    public function AuthToken($token)
    {
        ///////////////////////////////////////////////////////////////////////////////////
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user_token WHERE token=:utoken");
        $stmt->bindparam(":utoken", $token);
        $stmt->execute();
        $counter = $stmt->rowCount();
        if ($counter == 0) {
            return array("message" => "Authorization token doesn't exist", "success" => false);
        } else {
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $token_generated = $row["token_generated"];
            $expiry_date = $row["expiry_date"];
            $expires = $row["expires"];
            $is_active = $row["is_active"];
            $created = $row["created"];
        }
        $dtoken = $this->utils->decrypt($token);
        $keys =  explode("&", $dtoken);
        if (empty($dtoken)) {
            return array("message" => "Invalid authorization token", "success" => false);
        } else if (!count($keys) == 3) {
            return array("message" => "Invalid authorization token", "success" => false);
        }
        $companyid = $keys[0];
        $userid = $keys[1];
        $timestamp = $keys[2];
        ///////////////////////////////////
        if (!($timestamp == $token_generated)) {
            return array("message" => "Invalid authorization token", "success" => false);
        } else if ($expires && !is_null($expiry_date) && $this->utils->isExpired($expiry_date)) {
            return array("message" => "Authorization token expired", "success" => false);
        }
        return array(
            "token" =>  $token,
            "companyid" => $companyid,
            "userid"  => $userid,
            "token_generated" => $token_generated,
            "expiry_date" => $expiry_date,
            "expires" => $expires,
            "timestamp"  => $timestamp,
            "is_active" => $is_active,
            "created" => $created,
            "message" => "",
            "success" => true

        );
    }

    public function TokenExists($token)
    {
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user_token WHERE token=:utoken AND is_active=true");
        $stmt->bindparam(":utoken", $token);
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            return true;
        } else {
            return false;
        }
    }

    public function DisableUserToken($tokenid)
    {
        ///////////////////////////////////
        $stmt = $this->dbutils->runQuery("UPDATE pm_user_token SET is_active=false WHERE id=:utokenid");
        $stmt->bindparam(":utokenid", $tokenid);
        if ($stmt->execute()) {
            return true;
        } else {
            die($this->Response(["message" => "Something went wrong, please try again laiter", "success" => false], 400));
        }
    }

    public function DisableAllUserToken($userid)
    {
        ///////////////////////////////////
        $stmt = $this->dbutils->runQuery("UPDATE pm_user_token SET is_active=false WHERE user_id=:uuserid AND is_active=true");
        $stmt->bindparam(":uuserid", $userid);
        if ($stmt->execute()) {
            return true;
        } else {
            die($this->Response(["message" => "Something went wrong, please try again laiter", "success" => false], 400));
        }
    }

    public function UserHasValidToken($userid)
    {
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user_token WHERE user_id=:uuserid AND is_active=true");
        $stmt->bindparam(":uuserid", $userid);
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $expires = $row["expires"];
            $expiry_date = $row["expiry_date"];
            if (!$expires) {
                return true;
            } else if ($expiry_date == null) {
                return true;
            } else {
                if ($this->utils->isExpired($expiry_date)) {
                    return false;
                } else {
                    return true;
                }
            }
        } else {
            return false;
        }
    }

    public function UserHasToken($userid)
    {
        $stmt = $this->dbutils->runQuery("SELECT * FROM pm_user_token WHERE user_id=:uuserid AND is_active=true");
        $stmt->bindparam(":uuserid", $userid);
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            return true;
        } else {
            return false;
        }
    }


    public function getTokenByToken()
    {
        /////
        /////
    }

    public function _initSessionToken($token)
    {
        /////////////////////////////
        if (!$this->utils->is_session_started()) session_start();
        $_SESSION["AUTH_KEY"] = $token;
    }



    public function getAuthToken()
    {
        // TO-DO: Get Token
        // params
        // headers
        // sessions
        $headers = $this->decodeHeaders();
        /////////////////////////////////
        if ($this->purge('authKey')) {
            $authKey = trim($this->request('authKey'));
            if (empty($authKey) || is_null($authKey)) {
                return array("message" => "Authorisation token is required", "success" => false);
            } else {
                return $this->AuthToken($authKey);
            }
        } else  if ($this->purge('apiKey')) {
            $authKey = trim($this->request('apiKey'));
            if (empty($authKey) || is_null($authKey)) {
                return array("message" => "Authorisation token is required", "success" => false);
            } else {
                return $this->AuthToken($authKey);
            }
        } else if (array_key_exists("Authorization", $headers)) {
            $Authorization = explode(" ", $headers["Authorization"]);
            if (count($Authorization) == 2) {
                $authKey = trim($Authorization[1]);
                if (empty($authKey) || is_null($authKey)) {
                    return array("message" => "Authorisation token is required", "success" => false);
                } else {
                    return $this->AuthToken($authKey);
                }
            } else {
                return array("message" => "Invalid authorisation token", "success" => false);
            }
        } else if (array_key_exists("AUTH_KEY", $headers)) {
            $authKey =  trim($headers["AUTH_KEY"]);
            if (empty($authKey) || is_null($authKey)) {
                return array("message" => "Authorisation token is required", "success" => false);
            } else {
                return $this->AuthToken($authKey);
            }
        } else if (array_key_exists("API_KEY", $headers)) {
            $authKey =  trim($headers["API_KEY"]);
            if (empty($authKey) || is_null($authKey)) {
                return array("message" => "Authorisation token is required", "success" => false);
            } else {
                return $this->AuthToken($authKey);
            }
        } else {
            if (!$this->utils->is_session_started()) session_start();
            if (isset($_SESSION["AUTH_KEY"])) {
                $authKey =  trim($_SESSION["AUTH_KEY"]);
                if (empty($authKey) || is_null($authKey)) {
                    return array("message" => "Authorisation token is required", "success" => false);
                } else {
                    return $this->AuthToken($authKey);
                }
            }
            return array("message" => "Authorisation token is required", "success" => false);
        }
    }

    public function Auth()
    {
        $auth = $this->getAuthToken();
        if ($auth["success"]) {
            $userid = intval($auth["userid"]);
            return $this->getUser($userid);
        } else {
            die($this->Response($auth, 400));
        }
    }

    public function isEmailValid($email)
    {
        return filter_var($email, FILTER_VALIDATE_EMAIL);
    }

    public function isWebsiteValid($website)
    {
        return filter_var($website, FILTER_VALIDATE_URL);
    }
    ////////
    public function Response($response, $status = 200)
    {
        header("Access-Control-Allow-Origin: *");
        header("Content-Type: application/json; charset=UTF-8");
        http_response_code($status);
        return json_encode($response);
    }

    public function PlainJson($response, $status = 200)
    {
        header("Access-Control-Allow-Origin: *");
        header("Content-Type: application/json; charset=UTF-8");
        http_response_code($status);
        return $response;
    }

    /////
    public function JsonResponse($response, $status = 200)
    {
        header("Access-Control-Allow-Origin: *");
        header("Content-Type: application/json; charset=UTF-8");
        http_response_code($status);
        return json_encode($response);
    }
}
