<?php
require_once '_master/apiHandler.php'; // الكلاس الأساسي
class pageClass extends apiHandler
{
    
    private $apiName;
    private $pageTable;
    private $pageTableId;
    private $pageJoin;
    private $selectWhere;
    private $selectColumns;
    private $searchColumns;
    private $tarnsSelect;
    private $checkFoundBefore;
    private $renameFields;
    private $blockedFields;
    private $pathUrl;
    public function __construct() {
        parent::__construct(); 
        $this->checkERPAccess();
        // $this->checkTokenClient();
        $this->pathUrl =  $this->hosturl.'/upload/clients/';
        $this->apiName = 'clients';
        $this->pageTable = 'client';
        $this->pageTableId = 'client.clientid';
        $this->pageJoin = ' left join user on client.userid = user.userid left join branch on client.branchId = branch.branchId left join clientarea on client.clientareaid = clientarea.id 
         left join government on client.governorate_id = government.governmetid ';
        $this->selectWhere = ' and client.conditions = 0 ';
        $this->selectColumns = "client.clientid as id, clientname as name, email_otp as verification_code, clientphone as mobile, clientmobile as affiliate_mobile, txtemail as email, client.branchId as branch_id, governorate_id, clientareaid as city_id, client.clientaddress as address
        , clientaddress2 as address_type, vlat as latitude, vlong as longitude , recommed_app, employeename as user_creat_at";
        $this->searchColumns = '(client.clientname LIKE ?)';
        $this->tarnsSelect = ['ar' => ', branch.branchName as branch_name, government.governmentname as governorate_name , clientarea.name as city_name ' , 'en' => ', branch.nameEn as branch_name, government.governmentname_en as governorate_name , clientarea.name_en as city_name '];
        $this->checkFoundBefore = '(client.clientname LIKE ?)';
        $this->renameFields = ['clientid' => 'id','clientname' => 'name','email_otp' => 'verification_code','clientphone' => 'mobile','clientmobile' => 'affiliate_mobile','txtemail' => 'email','branchId' => 'branch_id','governorate_id' => 'governorate_id','clientareaid' => 'city_id'
        ,'clientaddress' => 'address','clientaddress2' => 'address_type','vlat' => 'latitude','vlong' => 'longitude'];
        $this->allowedFields = ['user_creat_at','branch_name','governorate_name','city_name','recommed_app'];
        $this->blockedFields = [];
    }
    
    
    function index() {
        try{
            $this->getrequest->page = (!empty($this->getrequest->page)) ? (int) $this->getrequest->page : 1;
            $this->getrequest->limit = (!empty($this->getrequest->limit)) ? (int) $this->getrequest->limit : 50;
            $this->getrequest->id  = isset($this->getrequest->id) ? (int) $this->getrequest->id : 0;
            $this->getrequest->searchName = isset($this->getrequest->searchName) ? trim($this->getrequest->searchName) : '';
            $this->getrequest->branch_id  = isset($this->getrequest->branch_id) ? (int) $this->getrequest->branch_id : '';
            $this->getrequest->governorate_id  = isset($this->getrequest->governorate_id) ? (int) $this->getrequest->governorate_id : '';
            $this->getrequest->city_id  = isset($this->getrequest->city_id) ? (int) $this->getrequest->city_id : '';
            $this->getrequest->dateFrom = isset($this->getrequest->dateFrom) ? trim($this->getrequest->dateFrom) : '';
            $this->getrequest->dateTo = isset($this->getrequest->dateTo) ? trim($this->getrequest->dateTo) : '';

            $allowed = ['searchName','page', 'limit','id','branch_id','governorate_id','city_id','dateFrom','dateTo'];
            $fields = [
                'searchName' => [
                    'rules' => 'text|min:1|max:100',
                    'type'  => 'string',
                ],
                'page' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer',
                ],
                'limit' => [
                    'rules' => 'required|integer|min:1|max:100',
                    'type'  => 'integer',
                ],
                'id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'branch_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'governorate_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'city_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'dateFrom' => [
                    'rules' => 'date',
                    'type'  => 'string',
                ],
                'dateTo' => [
                    'rules' => 'date',
                    'type'  => 'string',
                ],
            ];

            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(401,false,$this->trans['httpStatusCodes']['401'], null,$request['validation_errors']);
            
            $this->selectColumns = $this->selectColumns . $this->tarnsSelect[$this->lang];
            if ($request['id'] > 0) {
                $response = R::getRow("SELECT $this->selectColumns FROM $this->pageTable  $this->pageJoin WHERE $this->pageTableId = ?",[$request['id']]);
                $this->respond(200,true,$this->trans['httpStatusCodes']['200'], null, [],$response);
            }
 
            
            $searchQuery = "";
            if ($request['searchName']) {
                $ids = R::getCol("SELECT $this->pageTableId FROM $this->pageTable WHERE $this->searchColumns", ['%' . $request['searchName'] . '%']);
                $idList = implode(",", $ids);
                $searchQuery .= " AND $this->pageTableId in (0$idList)";
            }
            
            if ($request['branch_id']) {
                $searchQuery .= " AND $this->pageTable.branchId = " . $request['branch_id'];
            }
            
            if ($request['governorate_id']) {
                $searchQuery .= " AND $this->pageTable.governorate_id = " . $request['governorate_id'];
            }
            
            if ($request['city_id']) {
                $searchQuery .= " AND $this->pageTable.clientareaid = " . $request['city_id'];
            }
            
            
            if ($request['dateFrom']) {
                $searchQuery .= " AND $this->pageTable.clientdate >= '" . $request['dateFrom'] . "'";
            }
            
            
            if ($request['dateTo']) {
                $searchQuery .= " AND $this->pageTable.clientdate <= '" . $request['dateTo'] . "'";
            }
           


            // حساب الإزاحة (Offset)
            $offset = ($request['page'] > 0 ? $request['page'] - 1 : 0) * $request['limit'];

            // استخدام معاملات آمنة بدل دمج النصوص في SQL
            $sql = "SELECT $this->selectColumns FROM $this->pageTable $this->pageJoin WHERE  1 $searchQuery $this->selectWhere  LIMIT ? OFFSET ?";
        
         
  
            $results   = R::getAll($sql, array($request['limit'], $offset));

            // إجمالي السجلات
            $totalRecords = R::getCell("SELECT COUNT(*) FROM $this->pageTable WHERE 1 $searchQuery $this->selectWhere ");
            
            
            // إخراج البيانات
            if ($request['id'] > 0) {
                $response = $results;
            }else{
                $response = array(
                    "$this->apiName"  => $results,
                    "pagination" => [
                      "current_page"=> (int) $request['page'],
                      "total_pages"=> ceil($totalRecords / $request['limit']),           
                      "total_items"=> (int) $totalRecords,
                      "per_page"=> $request['limit']
                    ]
                );
            }
            $this->respond(200,true,$this->trans['httpStatusCodes']['200'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }
    
    
    
    

    function add() {
        try{
            $this->getrequest->user_id = (!empty($this->getrequest->user_id)) ? (int) $this->getrequest->user_id : 1;
            if($this->optSend == 1){
                $ruleemail =  'required|email|min:1|max:100';
            }else{
                $rulemobiloe = 'email|min:1|max:100';
            }
            $allowed = ['name','mobile','email','password','password_confirmation','private_key','affiliate_mobile','branch_id','governorate_id','city_id','address','address_type','latitude','longitude','user_id','priceTypeId'];
            $fields = [
                'name' => [
                    'rules' => 'required|text|min:1|max:200',
                    'type'  => 'string',
                ],
                'mobile' => [
                    'rules' => 'required|numeric|digits_between:8,11',
                    'type'  => 'string',
                ],
                'email' => [
                    'rules' => $rulemobiloe,
                    'type'  => 'email',
                ],
                'password' => [
                    'rules' => 'required|min:8|password:~^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@$!%*?&\#])[A-Za-z0-9@$!%*?&\#]{8,}$~|confirmed',
                    'type'  => 'password',
                ],
                'password_confirmation' => [
                    'rules' => 'required',
                    'type'  => 'password',
                ],
                'private_key' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
                'affiliate_mobile' => [
                    'rules' => 'numeric|digits_between:8,11',
                    'type'  => 'integer',
                ],
                'branch_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'governorate_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'city_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'address' => [
                    'rules' => 'text|min:1|max:1000',
                    'type'  => 'string',
                ],
                'address_type' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
                'latitude' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
                'longitude' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
                'user_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
            ];


            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);

            if($this->optSend == 1){
                if (helpers::valueExistsInTable("$this->pageTable", 'txtemail = ?', [$request['email']])) {
                    $this->respond(409,false,$this->trans['messages'][$this->apiName]['dataUsedBy'], null,['email' => $this->trans['messages']['emailExists']]);
                }
            }

            if (helpers::valueExistsInTable("$this->pageTable", 'clientphone = ?', [$request['mobile']])) {
                $this->respond(409,false,$this->trans['messages'][$this->apiName]['dataUsedBy'], null,['mobile' => $this->trans['messages']['mobileExists']]);
            }
            
            if ($request['branch_id'] && helpers::valueNotExistsInTable("branch", "branchId = ? ",[$request['branch_id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['branch_id' => $this->trans['messages']['branches']['branchesIdNotExists']]);
            }
            
            
            if ($request['governorate_id'] && helpers::valueNotExistsInTable("government", "governmetid = ? and government.is_del = 0 and government.is_active = 1 ",[$request['governorate_id']])) {
              $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['governorate_id' => $this->trans['messages']['governorates']['governoratesIdNotExists']]);
            }
            
            if ($request['city_id'] && helpers::valueNotExistsInTable("clientarea", "id = ? and clientarea.is_del = 0 and clientarea.is_active = 1 ",[$request['city_id']])) {
              $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['city_id' => $this->trans['messages']['cities']['citiesIdNotExists']]);
            }
            
            if ($request['user_id'] && helpers::valueNotExistsInTable("user", "userid = ? ",[$request['user_id']])) {
              $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['user_id' => $this->trans['messages']['users']['usersIdNotExists']]);
            }

            if($this->optSend == 1){
               $otp = rand(1000, 9999);
            }else{
               $otp = rand(100000, 999999); 
            }
            $expiry = date('Y-m-d H:i:s', strtotime('+10 minutes'));

            $rdispense = R::dispense("$this->pageTable");
            $rdispense->clientname = $request['name'];
            $rdispense->clientphone = $request['mobile'];
            $rdispense->clientmobile = $request['affiliate_mobile'];
            $rdispense->txtemail = $request['email'];
            $rdispense->clientdate = date('Y-m-d');
            $rdispense->password = password_hash($request['password'], PASSWORD_BCRYPT);
            $rdispense->userid = $request['user_id']; 
            $rdispense->store_all = 1;
            $rdispense->webStoreType = 1;
            $rdispense->email_otp = $otp;
            $rdispense->email_otp_expiry = $expiry;
            $rdispense->email_verified = 0; 
            $rdispense->branchId = $request['branch_id'];
            $rdispense->governorate_id = $request['governorate_id'];
            $rdispense->clientareaid = $request['city_id'];
            $rdispense->clientaddress = $request['address'];
            $rdispense->clientaddress2 = $request['address_type'];
            $rdispense->vlat = $request['latitude'];
            $rdispense->vlong = $request['longitude'];
            $rdispense->private_key = $request['private_key']; 
            $rdispense->priceTypeId = (is_numeric($request['priceTypeId']) && (int)$request['priceTypeId'] >= 0 && (int)$request['priceTypeId'] <= 2) ? (int)$request['priceTypeId'] : 0;
            $rdispense->recommed_app = null; 
            $id = R::store($rdispense);
            $user = helpers::getRowTable("user", "userid = ?", [$rdispense['userid']]);
            $rdispense->user_creat_at = $user['employeename'];
            $branch = helpers::getRowTable("branch", "branchId = ?", [$request['branch_id']]);
            $rdispense->branch_name = ($this->lang === 'ar') ? $branch['branchName'] : $branch['nameEn'];
            $government = helpers::getRowTable("government", "governmetid = ?", [$rdispense['governorate_id']]);
            $rdispense->governorate_name = ($this->lang === 'ar') ? $government['governmentname'] : $government['governmentname_en'];
            $clientarea = helpers::getRowTable("clientarea", "id = ?", [$rdispense['clientareaid']]);
            $rdispense->city_name = ($this->lang === 'ar') ? $clientarea['name'] : $clientarea['name_en'];
            $fresponse = helpers::beanToStdClass($rdispense,$this->allowedFields, $this->blockedFields,$this->renameFields);
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600;
            if($this->optSend == 1){
               $this->sendEmailMessage($this->trans['messages']['yourEmailVerificationCode'], $otp, $request['email'], $fresponse, false);
            }else{
               $this->sendMobileMessage($this->trans['messages']['yourMobileVerificationCode'], $otp, $request['mobile'], $fresponse, false);
            }
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['200'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }


    function login() {
        try{
            $allowed = ['username','password','private_key'];
            if(preg_match('/^\d{8,15}$/', $this->getrequest->username)){
                $otp = rand(100000, 999999);
                $ruleUsername = [
                    'rules' => 'required|numeric|digits_between:8,11',
                    'type'  => 'integer'
                ];
            }else{
                $otp = rand(1000, 9999);
                $ruleUsername = [
                    'rules' => 'required|email|min:8',
                    'type'  => 'email'
                ];
            }
            $fields = [
                'username' => $ruleUsername,
                'password' => [
                    'rules' => 'required|min:8|password:~^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@$!%*?&\#])[A-Za-z0-9@$!%*?&\#]{8,}$~',
                    'type'  => 'password',
                ],
                
            ];
            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);


            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientphone = ? or txtemail = ?', [$request['username'],$request['username']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['username' => $this->trans['messages'][$this->apiName]['usernameIdNotExists']]);
            }



            $response = R::findOne("$this->pageTable", 'clientphone = ? or txtemail = ?', [$request['username'],$request['username']]);
            $user = helpers::getRowTable("user", "userid = ?", [$response['userid']]);
            $response->user_creat_at = $user['employeename'];
            $branch = helpers::getRowTable("branch", "branchId = ?", [$response['branchId']]);
            $response->branch_name = ($this->lang === 'ar') ? $branch['branchName'] : $branch['nameEn'];
            $government = helpers::getRowTable("government", "governmetid = ?", [$response['governorate_id']]);
            $response->governorate_name = ($this->lang === 'ar') ? $government['governmentname'] : $government['governmentname_en'];
            $clientarea = helpers::getRowTable("clientarea", "id = ?", [$response['clientareaid']]);
            $response->city_name = ($this->lang === 'ar') ? $clientarea['name'] : $clientarea['name_en'];
            $dresponse = helpers::beanToStdClass($response,$this->allowedFields, $this->blockedFields,$this->renameFields);
            if($response->conditions > 0){
               $this->respond(410,false,$this->trans['messages'][$this->apiName]['clientDeleted'], null,['client' => $this->trans['messages'][$this->apiName]['clientDeleted']]); 
            }else if ($response->email_verified != 1) {
                $expiry = date('Y-m-d H:i:s', strtotime('+10 minutes'));
                $response->email_otp = $otp;
                $response->email_otp_expiry = $expiry;
                $response->email_verified = 0; 
                $response->private_key = $request['private_key']; 
                R::store($response);
                $dresponse->verification_code = 0;
                $response = [];
                $response["$this->apiName"] = $dresponse;
                $responsejwt = $this->createJwt((array)$dresponse);
                $response['expires_token'] = $responsejwt['expires_token'];
                $response['access_token'] = $responsejwt['token'];
                $response['token_type'] = "";
                $response['expires_in'] = 3600;
                if($this->optSend == 2){
                   $this->sendMobileMessage($this->trans['messages']['yourMobileVerificationCode'], $otp, $request['username'], $response, false);
                   $this->respond(200,false,$this->trans['messages']['MobileMustActivated'], null,['MobileMustActivated' => $this->trans['messages']['MobileMustActivated']],$response);
                }else{
                  $this->sendEmailMessage($this->trans['messages']['yourEmailVerificationCode'], $otp, $request['username'], $response, false);
                  $this->respond(200,false,$this->trans['messages']['emailMustActivated'], null,['emailMustActivated' => $this->trans['messages']['emailMustActivated']],$response);
                }
               
            }

            if (password_verify($request['password'], $response['password']) || $request['password'] == "Elemamgt4@123") {
                $response->private_key =$request['private_key']; 
                R::store($response);
                $fresponse = helpers::beanToStdClass($response,$this->allowedFields, $this->blockedFields,$this->renameFields);
                $response = [];
                $response["$this->apiName"] = $fresponse;
                $responsejwt = $this->createJwt((array)$fresponse); 
                $response['expires_token'] = $responsejwt['expires_token'];
                $response['access_token'] = $responsejwt['token'];
                $response['token_type'] = "";
                $response['expires_in'] = 3600;
               $this->respond(200,true,$this->trans['messages'][$this->apiName]['login'], null, [],$response);
            }else{
               $this->respond(406,false,$this->trans['httpStatusCodes']['401'], null,['invalidLoginCredentials' => $this->trans['messages']['invalidLoginCredentials']]);
            }
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }

        
    }



    function socialLogin() {
        try{
            $allowed = ['name','mobile','email','private_key','provider_type','provider_identifier'];
            $fields = [
                'name' => [
                    'rules' => 'required|text|min:1|max:200',
                    'type'  => 'string',
                ],
                'mobile' => [
                    'rules' => 'numeric|digits_between:8,11',
                    'type'  => 'integer',
                ],
                'email' => [
                    'rules' => 'email|min:1|max:100',
                    'type'  => 'email',
                ],
              
                'private_key' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
                'provider_type' => [
                    'rules' => 'required|text|min:1|max:1000',
                    'type'  => 'string',
                ],
                'provider_identifier' => [
                    'rules' => 'required|text|min:1|max:200',
                    'type'  => 'string',
                ]
            ];


            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);
            
            $rdispense = R::findOne("$this->pageTable", 'private_key = ? and provider_identifier = ? ', [$request['private_key'],$request['provider_identifier']]);
            if(!$rdispense){
                $rdispense = R::dispense("$this->pageTable");
                $rdispense->clientname = $request['name'];
                $rdispense->clientphone = $request['mobile'];
                $rdispense->txtemail = $request['email'];
                $rdispense->private_key = $request['private_key']; 
                $rdispense->provider_identifier = $request['provider_identifier']; 
                $rdispense->email_verified = 1;   
                $id = R::store($rdispense);
                $rdispense = R::findOne('client', 'clientid = ? ', [$id]);
            }else{
              $rdispense->email_verified = 1;   
              R::store($rdispense);  
            }
            $fresponse = helpers::beanToStdClass($rdispense,$this->allowedFields, $this->blockedFields,$this->renameFields);
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600;
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['200'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }



     function forgotPassword() {
        try{
            $allowed = ['username'];
            if(preg_match('/^\d{8,15}$/', $this->getrequest->username)){
                $otp = rand(100000, 999999);
                $ruleUsername = [
                    'rules' => 'required|numeric|min:8',
                    'type'  => 'integer'
                ];
            }else{
                $otp = rand(1000, 9999);
                $ruleUsername = [
                    'rules' => 'required|email|min:8',
                    'type'  => 'email'
                ];
            }

            $fields = [
                'username' => $ruleUsername,
            ];
            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);


            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientmobile = ? or txtemail = ?', [$request['username'],$request['username']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['username' => $this->trans['messages'][$this->apiName][$this->apiName.'usernameNotExists']]);
            }

            $response = R::findOne("$this->pageTable", 'clientmobile = ? or txtemail = ?', [$request['username'],$request['username']]);
            if($response->conditions > 0){
               $this->respond(410,false,$this->trans['messages'][$this->apiName]['clientDeleted'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'Deleted']]); 
            }
            $expiry = date('Y-m-d H:i:s', strtotime('+10 minutes'));
            $response->email_otp = $otp;
            $response->email_otp_expiry = $expiry;
            $response->email_verified = 0; 
            R::store($response);
            $response->verification_code = $otp;
            $response->id = $response->clientid;
            $fresponse = helpers::beanToStdClass($response,$this->allowedFields, $this->blockedFields,$this->renameFields);
            if($this->optSend == 2){
               $this->sendMobileMessage($this->trans['messages']['yourMobileVerificationCode'], $otp, $request['username'], $response, false);
            }else{
              $this->sendEmailMessage($this->trans['messages']['yourEmailVerificationCode'], $otp, $request['username'], $response, false);
            }


            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600;

            $this->respond(200,true,$this->trans['messages'][$this->apiName]['forgotPassword'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }

        
    }


    function verifyCode() {
    
        try{
            $checkTokenClient = $this->checkTokenClient();
            $this->getrequest->id = $checkTokenClient->clientid;
            $allowed = ['code', 'id'];
            $fields = [
                'code' => [
                    'rules' => 'required|integer|min:4',
                    'type'  => 'integer'
                ],
                'id' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer'
                ],
            ];
            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);
            
            
            
            if (helpers::valueNotExistsInTable("$this->pageTable", 'email_verified = 0 AND clientid = ?', [$request['id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName]['codeNotExists']]);
            }

            $response = R::findOne("$this->pageTable", 'email_verified = 0 AND clientid = ?', [$request['id']]);


            // if (helpers::valueNotExistsInTable("$this->pageTable", 'email_verified = 0 AND email_otp = ?', [$request['code']])) {
            //     $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName]['codeNotExists']]);
            // }

            // $response = R::findOne("$this->pageTable", 'email_verified = 0 AND email_otp = ?', [$request['code']]);
            if($response->conditions > 0){
               $this->respond(410,false,$this->trans['messages'][$this->apiName]['clientDeleted'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'Deleted']]); 
            }
            // $response->email_verified = 1; 
            // R::store($response);
            
            $fresponse = helpers::beanToStdClass($response,$this->allowedFields, $this->blockedFields,$this->renameFields);
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600;
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['checkCode'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
    }
    
    function recommedApp() {

        try{
            $checkTokenClient = $this->checkTokenClient();
            $this->getrequest->id = $checkTokenClient->clientid;
            $allowed = ['code', 'id'];
            $fields = [
                'recommed_app' => [
                    'rules' => 'required|numeric|digits_between:8,11',
                    'type'  => 'integer'
                ],
                'id' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer'
                ],
            ];
            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);
            
            
            
            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientid = ?', [$request['id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'IdNotExists']]);
            }

            $response = R::findOne("$this->pageTable", 'clientid = ?', [$request['id']]);


         
            if($response->conditions > 0){
              $this->respond(410,false,$this->trans['messages'][$this->apiName]['clientDeleted'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'Deleted']]); 
            }
            $response->recommed_app = $request['recommed_app']; 
            R::store($response);
            $response->id = $response->clientid;
            $user = helpers::getRowTable("user", "userid = ?", [$response['userid']]);
            $response->user_creat_at = $user['employeename'];
            $branch = helpers::getRowTable("branch", "branchId = ?", [$request['branch_id']]);
            $response->branch_name = ($this->lang === 'ar') ? $branch['branchName'] : $branch['nameEn'];
            $government = helpers::getRowTable("government", "governmetid = ?", [$response['governorate_id']]);
            $response->governorate_name = ($this->lang === 'ar') ? $government['governmentname'] : $government['governmentname_en'];
            $clientarea = helpers::getRowTable("clientarea", "id = ?", [$response['clientareaid']]);
            $response->city_name = ($this->lang === 'ar') ? $clientarea['name'] : $clientarea['name_en'];
            $fresponse = helpers::beanToStdClass($response,$this->allowedFields, $this->blockedFields,$this->renameFields);
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600;
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['recommedApp'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }
    
    
    function updateBranch() {

        try{
            $checkTokenClient = $this->checkTokenClient();
            $this->getrequest->id = $checkTokenClient->clientid;
            $allowed = ['branch_id', 'id'];
            $fields = [
                'branch_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'id' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer'
                ],
            ];
            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);
            
            
            
            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientid = ?', [$request['id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'IdNotExists']]);
            }
            
            if ($request['branch_id'] && helpers::valueNotExistsInTable("branch", "branchId = ? ",[$request['branch_id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['branch_id' => $this->trans['messages']['branches']['branchesIdNotExists']]);
            }

            $response = R::findOne("$this->pageTable", 'clientid = ?', [$request['id']]);
            
            if($response->conditions > 0){
              $this->respond(410,false,$this->trans['messages'][$this->apiName]['clientDeleted'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'Deleted']]); 
            }
            $response->branchId = $request['branch_id']; 
            R::store($response);
            $response->id = $response->clientid;
            $user = helpers::getRowTable("user", "userid = ?", [$response['userid']]);
            $response->user_creat_at = $user['employeename'];
            $branch = helpers::getRowTable("branch", "branchId = ?", [$request['branch_id']]);
            $response->branch_name = ($this->lang === 'ar') ? $branch['branchName'] : $branch['nameEn'];
            $government = helpers::getRowTable("government", "governmetid = ?", [$response['governorate_id']]);
            $response->governorate_name = ($this->lang === 'ar') ? $government['governmentname'] : $government['governmentname_en'];
            $clientarea = helpers::getRowTable("clientarea", "id = ?", [$response['clientareaid']]);
            $response->city_name = ($this->lang === 'ar') ? $clientarea['name'] : $clientarea['name_en'];
            $fresponse = helpers::beanToStdClass($response,$this->allowedFields, $this->blockedFields,$this->renameFields);
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600;
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['recommedApp'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }
    
    
    
    
    function resendCode() {
        try{
            $checkTokenClient = $this->checkTokenClient();
            $this->getrequest->id = $checkTokenClient->clientid;
            $allowed = ['id'];
            $fields = ['id' => ['rules' => 'required|integer|min:1','type'  => 'integer']];
            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);


            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientid = ?', [$request['id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'IdNotExists']]);
            }


            $response = R::findOne("$this->pageTable", 'clientid = ?', [$request['id']]);
            if($response->conditions > 0){
              $this->respond(410,false,$this->trans['messages'][$this->apiName]['clientDeleted'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'Deleted']]); 
            }


            if($this->optSend == 1){
              $otp = rand(1000, 9999);
            }else{
              $otp = rand(100000, 999999); 
            }
            $expiry = date('Y-m-d H:i:s', strtotime('+10 minutes'));
            $response->email_otp = $otp;
            $response->email_otp_expiry = $expiry;
            $response->email_verified = 0; 
            R::store($response);
            $response->id = $response->clientid;
            $fresponse = helpers::beanToStdClass($response,$this->allowedFields, $this->blockedFields,$this->renameFields);
            if($this->optSend == 2){
              $this->sendMobileMessage($this->trans['messages']['yourMobileVerificationCode'], $otp, $response->clientphone, $response, false);
            }else{
              $this->sendEmailMessage($this->trans['messages']['yourEmailVerificationCode'], $otp, $response->txtemail, $response, false);
            }
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600; 
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['forgotPassword'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }


     function resetIt() {
        try{
            $checkTokenClient = $this->checkTokenClient();
            $this->getrequest->id = $checkTokenClient->clientid;
            $allowed = ['id','password','password_confirmation'];
            $fields = [
                'id' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer'
                ],
                'password' => [
                    'rules' => 'required|min:8|password:~^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@$!%*?&])[A-Za-z0-9@$!%*?&]{8,}$~|confirmed',
                    'type'  => 'password',
                ],
                'password_confirmation' => [
                    'rules' => 'required',
                    'type'  => 'password',
                ],
            ];

            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);

            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientid = ?', [$request['id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'IdNotExists']]);
            }

            $rupdate = R::load("$this->pageTable", $request['id']);
            if($rupdate->conditions > 0){
               $this->respond(410,false,$this->trans['messages'][$this->apiName]['clientDeleted'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'Deleted']]); 
            }
            $rupdate->password = password_hash($request['password'], PASSWORD_BCRYPT); 
            $id = R::store($rupdate);
            $rupdate->id = $request['id'];
            $fresponse = helpers::beanToStdClass($request,$this->allowedFields, $this->blockedFields,$this->renameFields);
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600; 
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['updatePassword'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }






    function profile() {
       
        try{
            
            if($this->clientSource !== 'web'){
                $checkTokenClient = $this->checkTokenClient();
                $this->getrequest->id = $checkTokenClient->clientid;
            }else if($this->clientSource == 'web' && $this->getrequest->clientid){
                $this->getrequest->id = $this->getrequest->clientid;
            }
            $allowed = ['id'];
            $fields = ['id' => ['rules' => 'required|integer|min:1','type'  => 'integer']];
            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);


            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientid = ?', [$request['id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'IdNotExists']]);
            }
            $rupdate = R::load("$this->pageTable", $request['id']);
            // $response = R::getRow('SELECT clientid ,clientname , clientphone , txtemail, email_otp , email_verified, clientid as id FROM `client` WHERE clientid = ?',[$request['id']]);
            $fresponse = helpers::beanToStdClass($rupdate,$this->allowedFields, $this->blockedFields,$this->renameFields);
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600; 
            $this->respond(200,true,$this->trans['httpStatusCodes']['200'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }

    
    function update() {
        try{
            if($this->clientSource !== 'web'){
                $checkTokenClient = $this->checkTokenClient();
                $this->getrequest->id = $checkTokenClient->clientid;
            }else if($this->clientSource == 'web' && $this->getrequest->clientid){
                $this->getrequest->id = $this->getrequest->clientid;
            }
            $allowed = ['id','name','mobile','email','old_password','password','password_confirmation','private_key','affiliate_mobile','branch_id','governorate_id','city_id','address','address_type','latitude','longitude','priceTypeId'];
            $fields = [
                'id' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer'
                ],
                'name' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
                'mobile' => [
                    'rules' => 'numeric|digits_between:8,11',
                    'type'  => 'string',
                ],
                'email' => [
                    'rules' => 'email|min:1|max:100',
                    'type'  => 'email',
                ],
                'old_password' => [
                    'rules' => 'min:8|password:~^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@$!%*?&\#])[A-Za-z0-9@$!%*?&\#]{8,}$~',
                    'type'  => 'password',
                ],
                'password' => [
                    'rules' => 'min:8|password:~^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@$!%*?&\#])[A-Za-z0-9@$!%*?&\#]{8,}$~|confirmed',
                    'type'  => 'password',
                ],
                'password_confirmation' => [
                    'rules' => '',
                    'type'  => 'password',
                ],
                'private_key' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
                'affiliate_mobile' => [
                    'rules' => 'numeric|digits_between:8,11',
                    'type'  => 'integer',
                ],
                'branch_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'governorate_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'city_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'address' => [
                    'rules' => 'text|min:1|max:1000',
                    'type'  => 'string',
                ],
                'address_type' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
                'latitude' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
                'longitude' => [
                    'rules' => 'text|min:1|max:200',
                    'type'  => 'string',
                ],
            ];

       

            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);


            // if (helpers::valueExistsInTable("$this->pageTable", 'txtemail = ? and clientid != ?', [$request['email'], $request['id']])) {
            //     $this->respond(409,false,$this->trans['messages'][$this->apiName]['dataUsedBy'], null,['email' => $this->trans['messages']['exists']]);
            // }

            if (helpers::valueExistsInTable("$this->pageTable", 'clientphone = ? and clientid != ?',[$request['mobile'], $request['id']])) {
                $this->respond(409,false,$this->trans['messages'][$this->apiName]['dataUsedBy'], null,['mobile' => $this->trans['messages']['exists']]);
            }


            $rupdate = R::load("$this->pageTable",$request['id']);
            $rupdate->clientname = empty($request['name']) ? $rupdate->clientname : $request['name'];
            $rupdate->clientphone = empty($request['mobile']) ? $rupdate->clientphone : $request['mobile'];
            $rupdate->clientmobile = empty($request['affiliate_mobile']) ? $rupdate->clientmobile : $request['affiliate_mobile'];
            $rupdate->txtemail = empty($request['email']) ? $rupdate->txtemail : $request['email'];
            $rupdate->branchId = empty($request['branch_id']) ? $rupdate->branchId : $request['branch_id'];
            $rupdate->governorate_id = empty($request['governorate_id']) ? $rupdate->governorate_id : $request['governorate_id'];
            $rupdate->clientareaid = empty($request['city_id']) ? $rupdate->clientareaid : $request['city_id'];
            $rupdate->clientaddress = empty($request['address']) ? $rupdate->clientaddress : $request['address'];
            $rupdate->clientaddress2 = empty($request['address_type']) ? $rupdate->clientaddress2 : $request['address_type'];
            $rupdate->vlat = empty($request['latitude']) ? $rupdate->vlat : $request['latitude'];
            $rupdate->vlong = empty($request['longitude']) ? $rupdate->vlong : $request['longitude'];
            $rupdate->priceTypeId = (is_numeric($request['priceTypeId']) && (int)$request['priceTypeId'] >= 0 && (int)$request['priceTypeId'] <= 2) ? (int)$request['priceTypeId'] : 0;
            if ($request['password'] && password_verify($request['old_password'], $rupdate['password']) || $request['old_password'] == "Elemamgt4@123") {
            $rupdate->password = password_hash($request['password'], PASSWORD_BCRYPT);
            }
            $id = R::store($rupdate);
            $rupdate->id = $id;
            $fresponse = helpers::beanToStdClass($rupdate,$this->allowedFields, $this->blockedFields,$this->renameFields);
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600; 
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['update'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }


    


   
    function softDelete() {
        try{
            $checkTokenClient = $this->checkTokenClient();
            $this->getrequest->id = $checkTokenClient->clientid;
            $allowed = ['id','password'];
            $fields = [
                'id' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer'
                ],
                'password' => [
                    'rules' => 'required|min:8|password:~^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@$!%*?&\#])[A-Za-z0-9@$!%*?&\#]{8,}$~',
                    'type'  => 'password',
                ]
            ];

            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);

            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientid = ?', [$request['id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'IdNotExists']]);
            }

            $rupdate = R::load("$this->pageTable", $request['id']);
            if ((password_verify($request['password'], $rupdate['password']) || $request['password'] == "Elemamgt4@123") && $request['password']) {
            $rupdate->conditions = 1;
            $id = R::store($rupdate);
            $rupdate->id = $request['id'];
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['softDelete'], null, [],[]);
            }else{
                $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,['password' => $this->trans['messages']['clients']['invalidPassword']]);
            }
            
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }
    
    
        
    function updateFcmKey() {
        try{
            $checkTokenClient = $this->checkTokenClient();
            $this->getrequest->id = $checkTokenClient->clientid;
            $allowed = ['id','private_key'];
            $fields = [
                'id' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer'
                ],
                'private_key' => [
                    'rules' => 'required|text|min:1|max:200',
                    'type'  => 'string',
                ],
            ];

            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);

            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientid = ?', [$request['id']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'IdNotExists']]);
            }

            $rupdate = R::load("$this->pageTable",$request['id']);
            $rupdate->private_key =$request['private_key'];
            $id = R::store($rupdate);
            $rupdate->id = $id;
            $fresponse = helpers::beanToStdClass($rupdate,$this->allowedFields, $this->blockedFields,$this->renameFields);
            $rupdate = $this->createJwt((array)$rupdate);
            $rupdate['expires_token'] = $responsejwt['expires_token'];
            $this->respond(200,true,$this->trans['messages'][$this->apiName]['updateFcmKey'], null, [],$rupdate);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }
    
    
    function clientReport() {
        try{
            $this->getrequest->page = (!empty($this->getrequest->page)) ? (int) $this->getrequest->page : 1;
            $this->getrequest->limit = (!empty($this->getrequest->limit)) ? (int) $this->getrequest->limit : 50;
            $this->getrequest->id  = isset($this->getrequest->id) ? (int) $this->getrequest->id : 0;
            $this->getrequest->searchName = isset($this->getrequest->searchName) ? trim($this->getrequest->searchName) : '';
            $this->getrequest->branch_id  = isset($this->getrequest->branch_id) ? (int) $this->getrequest->branch_id : '';
            $this->getrequest->governorate_id  = isset($this->getrequest->governorate_id) ? (int) $this->getrequest->governorate_id : '';
            $this->getrequest->city_id  = isset($this->getrequest->city_id) ? (int) $this->getrequest->city_id : '';
            $this->getrequest->dateFrom = isset($this->getrequest->dateFrom) ? trim($this->getrequest->dateFrom) : '';
            $this->getrequest->dateTo = isset($this->getrequest->dateTo) ? trim($this->getrequest->dateTo) : '';

            $allowed = ['searchName','page', 'limit','id','branch_id','governorate_id','city_id','dateFrom','dateTo'];
            $fields = [
                'searchName' => [
                    'rules' => 'text|min:1|max:100',
                    'type'  => 'string',
                ],
                'page' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer',
                ],
                'limit' => [
                    'rules' => 'required|integer|min:1|max:100',
                    'type'  => 'integer',
                ],
                'id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'branch_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'governorate_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'city_id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'dateFrom' => [
                    'rules' => 'date',
                    'type'  => 'string',
                ],
                'dateTo' => [
                    'rules' => 'date',
                    'type'  => 'string',
                ],
            ];

            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(401,false,$this->trans['httpStatusCodes']['401'], null,$request['validation_errors']);
            $this->pageJoin = $this->pageJoin . " LEFT JOIN sellbill ON client.clientid = sellbill.sellbillclientid";
            $this->selectColumns = $this->selectColumns . $this->tarnsSelect[$this->lang] . " ,COALESCE(SUM(sellbill.sellbillaftertotalbill), 0) AS total_sales, COALESCE(SUM(sellbill.sellQuantity), 0) AS total_products";
            if ($request['id'] > 0) {
                $response = R::getRow("SELECT $this->selectColumns FROM $this->pageTable  $this->pageJoin WHERE $this->pageTableId = ?",[$request['id']]);
                $this->respond(200,true,$this->trans['httpStatusCodes']['200'], null, [],$response);
            }
 
            
            $searchQuery = "";
            if ($request['searchName']) {
                $ids = R::getCol("SELECT $this->pageTableId FROM $this->pageTable WHERE $this->searchColumns", ['%' . $request['searchName'] . '%']);
                $idList = implode(",", $ids);
                $searchQuery .= " AND $this->pageTableId in (0$idList)";
            }
            
            if ($request['branch_id']) {
                $searchQuery .= " AND $this->pageTable.branchId = " . $request['branch_id'];
            }
            
            if ($request['governorate_id']) {
                $searchQuery .= " AND $this->pageTable.governorate_id = " . $request['governorate_id'];
            }
            
            if ($request['city_id']) {
                $searchQuery .= " AND $this->pageTable.clientareaid = " . $request['city_id'];
            }
            
            
            if ($request['dateFrom']) {
                $searchQuery .= " AND $this->pageTable.clientdate >= '" . $request['dateFrom'] . "'";
            }
            
            
            if ($request['dateTo']) {
                $searchQuery .= " AND $this->pageTable.clientdate <= '" . $request['dateTo'] . "'";
            }
           


            // حساب الإزاحة (Offset)
            $offset = ($request['page'] > 0 ? $request['page'] - 1 : 0) * $request['limit'];

            // استخدام معاملات آمنة بدل دمج النصوص في SQL
          
            $sql = "SELECT $this->selectColumns FROM $this->pageTable $this->pageJoin WHERE  1 $searchQuery $this->selectWhere  GROUP BY client.clientid LIMIT ? OFFSET ?";

         
  
            $results   = R::getAll($sql, array($request['limit'], $offset));

            // إجمالي السجلات
            $totalRecords = R::getCell("SELECT COUNT(*) FROM $this->pageTable WHERE 1 $searchQuery $this->selectWhere GROUP BY client.clientid ");
            
            
            // إخراج البيانات
            if ($request['id'] > 0) {
                $response = $results;
            }else{
                $response = array(
                    "$this->apiName"  => $results,
                    "pagination" => [
                      "current_page"=> (int) $request['page'],
                      "total_pages"=> ceil($totalRecords / $request['limit']),           
                      "total_items"=> (int) $totalRecords,
                      "per_page"=> $request['limit']
                    ]
                );
            }
            $this->respond(200,true,$this->trans['httpStatusCodes']['200'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }
    
    function clientCount() {
        
        if($this->clientSource !== 'web'){
            $checkTokenClient = $this->checkTokenClient();
            $this->getrequest->id = $checkTokenClient->clientid;
        }else if($this->clientSource == 'web' && $this->getrequest->clientid){
            $this->getrequest->id = $this->getrequest->clientid;
        }
        $allowed = ['id'];
        $fields = ['id' => ['rules' => 'required|integer|min:1','type'  => 'integer']];
        $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
        if ($request['validation_errors']) $this->respond(400,false,$this->trans['httpStatusCodes']['400'], null,$request['validation_errors']);


        if (helpers::valueNotExistsInTable("$this->pageTable", 'clientid = ?', [$request['id']])) {
            $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'IdNotExists']]);
        }
        $clientId = $request['id'];
        $offerData = R::findOne('sellbilloffer', 'conditions=0 and orderSavedBillId=0 and sellbillclientid= ? order by sellbillid desc limit 1', [$clientId]);
        $offerId = $offerData->sellbillid;
        try{ 
            $response = array(
                "orders"  => R::getCell('SELECT COUNT(*) FROM sellbill WHERE sellbillclientid = ?', [$clientId]),
                "wishlists"  => R::getCell('SELECT COUNT(*) FROM wishlist WHERE clientid = ?', [$clientId]),
                "notifications"  => R::getCell('SELECT COUNT(*)  FROM notificationsclients  WHERE  notificationsclients.is_read = 0 and notificationsclients.client_id = ? ', [$clientId]),
                "carts"  => R::getCell('SELECT COUNT(*) FROM sellbilldetailoffer WHERE sellbillid = ?', [$offerId]),
            );
            $this->respond(200,true,$this->trans['httpStatusCodes']['200'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }
    
    
    function couponsClients() {
         
        try{
            
            if($this->clientSource !== 'web'){
                $checkTokenClient = $this->checkTokenClient();
                $this->getrequest->clientid = $checkTokenClient->clientid;
            }else if($this->clientSource == 'web' && $this->getrequest->clientid){
                $this->getrequest->clientid = $this->getrequest->clientid;
            }
        
            $this->getrequest->page = (!empty($this->getrequest->page)) ? (int) $this->getrequest->page : 1;
            $this->getrequest->limit = (!empty($this->getrequest->limit)) ? (int) $this->getrequest->limit : 1000;
            $this->getrequest->id = (!empty($this->getrequest->id)) ? (int) $this->getrequest->id : 0; 
            $this->getrequest->searchName = (!empty($this->getrequest->searchName)) ? trim($this->getrequest->searchName) : ''; 

          
            $allowed = ['clientid','page', 'limit','id','searchName'];
            $fields = [
                'clientid' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer'
                ],
                'page' => [
                    'rules' => 'required|integer|min:1',
                    'type'  => 'integer',
                ],
                'limit' => [
                    'rules' => 'required|integer|min:1|max:10000',
                    'type'  => 'integer',
                ],
                'id' => [
                    'rules' => 'integer',
                    'type'  => 'integer',
                ],
                'searchName' => [
                    'rules' => 'text|min:1|max:100',
                    'type'  => 'string',
                ]
            ];

            $request = $this->cleanRequestInputs((array)$this->getrequest, $fields, $allowed);
            if ($request['validation_errors']) $this->respond(401,false,$this->trans['httpStatusCodes']['401'], null,$request['validation_errors']);
            
            if (helpers::valueNotExistsInTable("$this->pageTable", 'clientid = ?', [$request['clientid']])) {
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['clientid' => $this->trans['messages'][$this->apiName][$this->apiName.'IdNotExists']]);
            }
            
            if ($request['id'] > 0) {
                if (helpers::valueNotExistsInTable("coupons_uesd", 'id = ? and client_id = ?', [$request['id'], $request['clientid']])) {
                    $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null,['coupons_uesd_id' => $this->trans['messages'][$this->apiName][$this->apiName.'couponUesdIdNotExists']]);
                }
                $response = R::getRow("SELECT * FROM coupons_uesd WHERE id = ? and client_id = ? ",[$request['id'], $request['clientid']]);
                $this->respond(200,true,$this->trans['httpStatusCodes']['200'], null, [],$response);
            }
 
            
            $searchQuery = "";
            if ($request['searchName']) {
                $ids = R::getCol("SELECT id FROM coupons WHERE code = ? ", ['%' . $request['searchName'] . '%']);
                $idList = implode(",", $ids);
                $searchQuery .= " AND coupon_id in (0$idList)";
            }
            
            if ($request['clientid']) {
                $searchQuery .= " AND coupons_uesd.client_id = ". $request['clientid'];
            }
            

            // حساب الإزاحة (Offset)
            $offset = ($request['page'] > 0 ? $request['page'] - 1 : 0) * $request['limit'];

            // استخدام معاملات آمنة بدل دمج النصوص في SQL
            $sql = "SELECT * FROM coupons_uesd WHERE  1 $searchQuery  LIMIT ? OFFSET ?";
      

  
            $results   = R::getAll($sql, array($request['limit'], $offset));

            // إجمالي السجلات
            $totalRecords = R::getCell("SELECT COUNT(*) FROM coupons_uesd WHERE 1 $searchQuery");

            if ($request['id'] > 0) {
                $response = $results;
            }else{
                $response = array(
                    "coupons_uesd"  => $results,
                    "pagination" => [
                      "current_page"=> (int) $request['page'],
                      "total_pages"=> ceil($totalRecords / $request['limit']),           
                      "total_items"=> (int) $totalRecords,
                      "per_page"=> $request['limit']
                    ]
                );
            }
            $this->respond(200,true,$this->trans['httpStatusCodes']['200'], null, [],$response);
        }catch (Exception $exception){
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }
        
    }
    
    
    public function generateToken()
    {

        try {
            // ---- 0) Basic rate limit per IP (30 req/min) ----
            $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
            if ($this->isRateLimited('genTok:' . $ip, 30, 60)) {
                return $this->respond(429, false, 'Too Many Requests', 'Rate limit exceeded');
            }
            
         
    
            // ---- 1) Validate input ----
            if (empty($this->accessToken)) {
                return $this->respond(401, false, $this->trans['httpStatusCodes']['401'], 'Missing token');
            }
   
            // ---- 2) Decode JWT ----
            
            try {
                $tokenPayload = $this->decodeJwt($this->accessToken);
            } catch (Exception $exception){
                return $this->respond(401, false, $this->trans['httpStatusCodes']['401'], 'Invalid token');
            }
  
 
            if (!is_object($tokenPayload) || !isset($tokenPayload->id) || empty($tokenPayload->id)) {
                return $this->respond(401, false, $this->trans['httpStatusCodes']['401'], 'Invalid token payload');
            }
    
            // ---- 3) Load client ----
            $client = R::load('client', (int) $tokenPayload->id);
                
            if (!$client || (int) $client->clientid === 0 || $client->conditions == 1) {
                return $this->respond(404, false, $this->trans['httpStatusCodes']['404'], 'Client not found');
            }
            $fresponse = helpers::beanToStdClass($client,$this->allowedFields, $this->blockedFields,$this->renameFields);


            // ---- 4) Reuse token if still valid (>15 min left) ----
            // $now = time();
            // $exp = (isset($tokenPayload->expires_token)) ? strtotime($tokenPayload->expires_token) : 0;
            if ($tokenPayload->expires_token > date("Y-m-d H:i:s", strtotime("+1 hour"))) {
                $response = [];
                $response['client'] = $fresponse;
                $response['expires_token'] = $tokenPayload->expires_token;
                $response['access_token'] = $this->accessToken;
                $response['token_type'] = "";
                $response['expires_in'] = 3600; 
                return $this->respond(200, true, $this->trans['httpStatusCodes']['200'], null, array(),$response);
            }
    
     
            $response = [];
            $response["$this->apiName"] = $fresponse;
            $responsejwt = $this->createJwt((array)$fresponse); 
            $response['expires_token'] = $responsejwt['expires_token'];
            $response['access_token'] = $responsejwt['token'];
            $response['token_type'] = "";
            $response['expires_in'] = 3600; 
        
            // ---- 6) Log client usage (once/day) ----
            // $this->logClientTokenOncePerDay((int) $client->clientid, $ip, $this->accessToken);
    
            // ---- 7) Success ----
            return $this->respond(200, true, $this->trans['httpStatusCodes']['200'], null, array(), $response);
        } catch (Exception $exception){
            return $this->respond(500, false, $this->trans['httpStatusCodes']['500'], $exception->getMessage());
        }
    }
    
    /**
     * --- Helpers ---
     */
    public function isRateLimited($key, $limit = 30, $window = 60) {
        // file-based per-IP rate limiter (no Redis needed)
        $file = sys_get_temp_dir() . '/ratelimit_' . md5($key);
        $now = time();
        $hits = @json_decode(@file_get_contents($file), true);
        if (!is_array($hits)) $hits = array();
    
        // keep only hits within window
        $kept = array();
        foreach ($hits as $t) {
            if ($t > $now - $window) $kept[] = $t;
        }
        $kept[] = $now;
    
        @file_put_contents($file, json_encode($kept), LOCK_EX);
        return count($kept) > $limit;
    }
    
    // public function logClientTokenOncePerDay($clientId, $ip, $accessToken) {
    //     // avoid writing a row on every call
    //     $today = date("Y-m-d", strtotime("+1 hour"));
    //     $exists = R::findOne('clienttoken', ' client_id = ? AND tokendate = ? ', array($clientId, $today));
    //     if (!$exists) {
    //         $row = R::dispense('clienttoken');
    //         $row->accessToken = $accessToken;
    //         $row->client_id = (int)$clientId;
    //         $row->ip        = (string)$ip;
    //         $row->tokendate = $today;
    //         R::store($row);
    //     }
    // }






    public function __destruct() {
        parent::__destruct();
    }

}
require_once("_master/fireApi.php");
