<?php
namespace App\Service;
use App\Core\Service\Logger;
use App\Core\Library\Mailer;
use App\Model\AdminTemplateModel;
use App\Model\AdminModel;
use App\Model\FxModel;
use App\Service\Api;
class Messaging
{
    private $AdminTemplateModel;
    private $AdminModel;
    private $FxModel;
    private $Mailer;
    private $phone_no;
    private $Api;
    public function __construct() {
        $this->AdminTemplateModel = new AdminTemplateModel();
        $this->AdminModel = new AdminModel();
        $this->Mailer = new Mailer();
        $this->FxModel = new FxModel();
        $this->Api        = new Api();  
    }
    
    private function saveEmailSmsLog($type, $body, $subject=NULL, $response=NULL, $ref_id=0, $ref_name=NULL, $user_id=0) {
        try {
            $data = ["type"=>$type, "body"=>$body];
            
            if(!empty($subject)) {
                $data['email_subject'] = $subject;
            }
            if(!empty($ref_id)) {
                $data['ref_id'] = $ref_id;
            }
            if(!empty($ref_name)) {
                $data['ref_name'] = $ref_name;
            }
            if(!empty($user_id)) {
                $data['sent_by'] = $user_id;
            }
            if(!empty($this->Mailer->email_to)) {
                $data['email_to'] = implode(",", $this->Mailer->email_to);
            }
            if(!empty($this->Mailer->email_cc)) {
                $data['email_cc'] = implode(",", $this->Mailer->email_cc);
            }
            if(!empty($this->Mailer->email_bcc)) {
                $data['email_bcc'] = implode(",", $this->Mailer->email_bcc);
            }
            if(!empty($this->Mailer->email_reply_to)) {
                $data['email_reply_to'] = implode(",", $this->Mailer->email_reply_to);
            }
            if(!empty($this->Mailer->attachments)) {
                $data['attachments'] = implode(",", $this->Mailer->attachments);
            }
            if(!empty($this->phone_no)) {
                $data['msg_to'] = implode(",", $this->phone_no);
            }
            if(!empty($response)) {
                $data['response'] = $response;
            }
            return $this->AdminModel->insert($this->AdminModel->tables['admin_email_sms_logs'], $data);
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }
    
    private function saveClientEmailSmsLog($comp_id, $user_id, $type, $body, $subject=NULL, $from=NULL, $to=NULL, $cc=NULL, $attachment=NULL, $response=NULL, $log_id=0, $ref_id=0, $ref_name=NULL) {
        try {
            $data = ["type"=>$type, "body"=>$body];
            
            if(!empty($subject)) {
                $data['email_subject'] = $subject;
            }
            if(!empty($ref_id)) {
                $data['ref_id'] = $ref_id;
            }
            if(!empty($ref_name)) {
                $data['ref_type'] = $ref_name;
            }
            if(!empty($user_id)) {
                $data['cr_usr'] = $user_id;
            }
            if(!empty($from)) {
                $data['from'] = $from;
            }
            if(!empty($to)) {
                $data['to'] = $to;
            }
            if(!empty($cc)) {
                $data['cc'] = $cc;
            }
            if(!empty($attachment)) {
                $data['attachment'] = $attachment;
            }
           
            if(!empty($response)) {
                $data['response'] = $response;
            }
            $dbname = $this->FxModel->client_db_prefix . $comp_id;
            if(empty($log_id)) {
                return $this->FxModel->insert($dbname.".".$this->FxModel->tables['email_sms_log'], $data);
            } else {
                return $this->FxModel->update($dbname.".".$this->FxModel->tables['email_sms_log'], $data, ['id'=>$log_id]);
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function setEmailSMSTemplate($baseStringKeys, $templatedbArray, $dataArray) {
        $replacvalue = [];
        foreach ($baseStringKeys as $baseKey) {
            $key = trim(str_replace(array('{{', '}}'), array('', ''), $baseKey));
            $replacvalue[] = (isset($dataArray["$key"])) ? $dataArray["$key"] : '';
        }
        
        $email_subject = $email_body = $sms_body = '';
        foreach ($templatedbArray as $temp) {
            if (strtoupper($temp['temp_type']) == 'EMAIL') {
                $email_subject = str_replace($baseStringKeys, $replacvalue, $temp['subject']);
                $emilBody = str_replace($baseStringKeys, $replacvalue, $temp['template_body']);
            } else if (strtoupper($temp['temp_type']) == 'SMS') {
                $sms_body = str_replace($baseStringKeys, $replacvalue, strip_tags($temp['template_body']));
            }
        }
        return array('email_subject' => $email_subject, 'email_body' => $emilBody, 'sms_body' => $sms_body);
    }
    
    public function sendMessageToTeaminspector($api_url, $phone_no, $msg, $file_path = '') {
        try {
            $ch = curl_init();
            $msg1 = curl_escape($ch, $msg);
            $url = str_replace(array('{0}', '{1}'), array($phone_no, $msg1), $api_url);
            
            $responseMsg = '';
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_ENCODING => '',
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 10,
                CURLOPT_SSL_VERIFYHOST => false,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_CUSTOMREQUEST => 'POST',
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1
            ]);
            if(!empty($file_path)) {
                if (!file_exists($file_path)) {
                    throw new \Exception("Attachment file does not exist.");
                }
                $mime_type = mime_content_type($file_path);
                $curl_file = new \CURLFile($file_path, $mime_type, 'attachment');
                curl_setopt($ch, CURLOPT_POSTFIELDS, ['attachment' => $curl_file]);
            }
            $curl_error = curl_error($ch);
            $response = curl_exec($ch);
            $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if (!empty($curl_error)) {
                throw new \Exception('API Error : ' . $curl_error);
            }
            if ($http_status != 200) {
                throw new \Exception('API Error Not getting 200 Status code: ' . strval($response));
            }
            echo $response;
            $resp = json_decode($response);
            if($resp->success == true) {
                return ["status"=>true];
            } else {
                throw new \Exception($resp->message);
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function sendAdminWhatsApp(Array $data, $ref_id=0, $ref_name="", $user_id=0) {
        try {
            $setting = $this->AdminModel->getAppSettings();
            if(!$setting['status']) {
                throw new \Exception($setting['error']);
            }
            if(empty($setting['data'])) {
                throw new \Exception("App settings data not found");
            }
            if(empty($setting['data']['whatsapp_no'])) {
                throw new \Exception("WhatsApp number is not configured");
            }
            if(empty($setting['data']['whatsapp_solution_provider'])) {
                throw new \Exception("WhatsApp solution provider is not configured");
            }
            if(!in_array($setting['data']['whatsapp_solution_provider'], ['teaminspector'])) {
                throw new \Exception("WhatsApp solution provider configured is invalid");
            }
            if(empty($setting['data']['whatsapp_api'])) {
                throw new \Exception("WhatsApp API URL is not configured");
            }
            if(empty($data['phone_no'])) {
                throw new \Exception("Phone No. required to send WhatsApp message");
            }
            if(empty($data['body'])) {
                throw new \Exception("Message body required to send WhatsApp message");
            }
            
            $responseMsg = [];
			$mobile_array = explode(',', $data['phone_no']);
            $this->phone_no = $mobile_array;
            foreach ($mobile_array as $key => $mobile) {
                $resp = '';
                if(strtolower($setting['data']['whatsapp_solution_provider']) == 'teaminspector') {
                    $team_resp = $this->sendMessageToTeaminspector($setting['data']['whatsapp_api'], $mobile, $data['body']);
                    if(empty($team_resp['status'])) {
                        $resp .= $team_resp['error'] . '<br>';
                    }
                }
                $responseMsg[] = ['phone_no'=>$mobile, 'message'=>!empty($resp) ? $resp : 'Message Sent'];
                $this->phone_no = '';
            }
            $this->phone_no = '';
            return ["status"=>true, "data"=>$responseMsg];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function sendAdminMessage(Array $data, $ref_id=0, $ref_name="", $user_id=0) {
        try {
            $setting = $this->AdminModel->getAppSettings();
            if(!$setting['status']) {
                throw new \Exception($setting['error']);
            }
            if(empty($setting['data'])) {
                throw new \Exception("App settings data not found");
            }
            if(empty($setting['data']['sms_api'])) {
                throw new \Exception("SMS API is not configured");
            }
            if(empty($data['phone_no'])) {
                throw new \Exception("Phone No. required to send SMS");
            }
            if(empty($data['body'])) {
                throw new \Exception("SMS body required to send SMS");
            }
            
            $responseMsg = [];
			$msg = str_replace(array("&nbsp;", " ", "'"), array(' ', ' ', '`'), $data['body']);
			$msg = str_replace(array('  '), array(' '), preg_replace('/[^A-Za-z0-9\<>?|_.:*#&$!(){;"%-+`}@=,\n\/ ]/', '', $msg));
			$mobile_array = explode(',', $data['phone_no']);
            $this->phone_no = $mobile_array;
            foreach ($mobile_array as $key => $mobile) {
                $resp = '';
                $ch = curl_init();
                $msg1 = curl_escape($ch, $msg);
                $url = str_replace(array('{0}', '{1}'), array($mobile, $msg1), $setting['data']['sms_api']);
                
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_TIMEOUT, 60);
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
                
                $curl_error = curl_error($ch);
                $response = curl_exec($ch);
                $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                curl_close($ch);
                if (!empty($curl_error)) {
                    $resp .= 'API Error : ' . $curl_error . "<br>";
                }
                if ($http_status != 200) {
                    $resp .= 'API Error Not getting 200 Status code: ' . strval($response);
                }
                $responseMsg[] = ['phone_no'=>$mobile, 'message'=>!empty($resp) ? $resp : 'SMS Sent'];
            }
            $this->phone_no = '';
            return ["status"=>true, "data"=>$responseMsg];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function sendAdminTemplateMessage(Array $data, Array $template_for, $is_whatsapp=false) {
        try {
            if(empty($data['phone_no'])) {
                throw new \Exception("Phone No. required to send SMS");
            }
            $template_str	= implode(",", $template_for);
            $where			= "t1.status=1 AND t1.temp_type='SMS' AND t2.template_for IN($template_str)";
            $dbrs = $this->AdminTemplateModel->getTemplateDetail($where);
            if(empty($dbrs['status'])) {
                throw new \Exception($dbrs['error']);
            }
            if(empty($dbrs['data'])) {
                throw new \Exception("template details not found");
            }
            $sent_count = 0;
            $resp = [];
            foreach($dbrs['data'] as $ky=>$row) {
                if(!empty($row['template_body'])) {
                    $template_name	= $row['template_for'];
                    $finalTemplate	= $this->setEmailSMSTemplate(array_keys($this->AdminTemplateModel->template_vars), array($row), $data);
                    $reference_id	= isset($data['reference_id'])?$data['reference_id']:0;
                    if (!empty($finalTemplate['sms_body'])) {
                        $data['body']		= $finalTemplate['sms_body'];
                        if(!empty($is_whatsapp)) {
                            $rsp = $this->sendAdminWhatsApp($data, $reference_id, $template_name, 0);
                        } else {
                            $rsp = $this->sendAdminMessage($data, $reference_id, $template_name, 0);
                        }
                        if (!empty($rsp['status'])) {
                            $sent_count++;
                            array_merge($resp, $rsp['data']);
                        } else {
                            Logger::error("Template message could not be sent. Template ID:".$row['id'], ['File' => __FILE__, 'Line'=>__LINE__]);
                        }
                    }
                } else {
                    Logger::error("Template Body is empty Template ID:".$row['id'], ['File' => __FILE__, 'Line'=>__LINE__]);
                }
            }
            if($sent_count == 0) {
                throw new \Exception("Template message could not be sent");
            }
            return ["status"=>true, "count"=>$sent_count, "data"=>$resp];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function sendAdminEmail(Array $data, $ref_id=0, $ref_name="", $user_id=0) {
        try {
            $setting = $this->AdminModel->getAppSettings();
            if(!$setting['status']) {
                throw new \Exception($setting['error']);
            }
            if(empty($setting['data'])) {
                throw new \Exception("App settings data not found");
            }
            if(empty($setting['data']['smtp_email_id'])) {
                throw new \Exception("SMTP email id is not configured");
            }
            if(empty($setting['data']['smtp_email_password'])) {
                throw new \Exception("SMTP password is not configured");
            }
            if(empty($setting['data']['smtp_email_server'])) {
                throw new \Exception("SMTP host name is not configured");
            }
            if(empty($setting['data']['smtp_port'])) {
                throw new \Exception("SMTP port is not configured");
            }
            $data['body'] = view('mailer/email_body', ['content'=>$data['body']]);
            $this->Mailer = new Mailer();
            $this->Mailer->configure($setting['data']['smtp_email_server'], $setting['data']['smtp_email_id'], $setting['data']['smtp_email_password'], $setting['data']['smtp_port'], $setting['data']['smtp_enable_ssl'], $setting['data']['smtp_verify_ssl']);
            $email_resp = $this->Mailer->sendEmail($data);
            $response = !empty($email_resp['status'])?$email_resp['data']:$email_resp['error']; 
            if(!empty($ref_id) || !empty($ref_name) || !empty($user_id)) {
                $res = $this->saveEmailSmsLog('EMAIL', $data['body'], $data['subject'], $response, $ref_id, $ref_name, $user_id);
                if(!$res['status']) {
                    Logger::error($res['error'], ['File' => __FILE__, 'Line'=>__LINE__]);
                }
            }
            return $email_resp;
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function sendAdminTemplateEmail(Array $data, Array $template_for) {
        try {
            $template_str	= implode(",", $template_for);
            $where			= "t1.status=1 AND t1.temp_type='Email' AND t2.template_for IN($template_str)";
            $dbrs = $this->AdminTemplateModel->getTemplateDetail($where);
            if(empty($dbrs['status'])) {
                throw new \Exception($dbrs['error']);
            }
            if(empty($dbrs['data'])) {
                throw new \Exception("Email template details not found");
            }
            $email_sent_count = 0;
            foreach($dbrs['data'] as $ky=>$row) {
                
                if(!empty($row['template_body']) && !empty($row['subject'])) {
                    $template_name	= $row['template_for'];
                    $finalTemplate	= $this->setEmailSMSTemplate(array_keys($this->AdminTemplateModel->template_vars), array($row), $data);
                    
                    $reference_id	= isset($data['reference_id'])?$data['reference_id']:0;
                    
                    if (!empty($finalTemplate['email_subject']) && !empty($finalTemplate['email_body'])) {
                        
                        $data['subject']	= $finalTemplate['email_subject'];
                        $data['body']		= $finalTemplate['email_body'];
                        $emailresp = $this->sendAdminEmail($data, $reference_id, $template_name, 0);
                        if (!empty($emailresp['status'])) {
                            $email_sent_count++;
                        } else {
                            Logger::error("Template email could not be sent. Template ID:".$row['id'], ['File' => "App\Service\Email.php", 'Method'=>'sendAdminTemplateEmail']);
                        }
                    }
                } else {
                    Logger::error("Template Body or Subject is empty Template ID:".$row['id'], ['File' => "App\Service\Email.php", 'Method'=>'sendAdminTemplateEmail']);
                }
            }
            if($email_sent_count == 0) {
                throw new \Exception("Template email could not be sent");
            }
            return ["status"=>true, "data"=>$email_sent_count];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function sendClientEmail($comp_id, $user_id, $setting, Array $data, $log_id, $ref_id=0, $ref_name="") {
        try {
            $data['body'] = view('mailer/email_body', ['content'=>$data['body']]);
            $this->Mailer = new Mailer();
            $this->Mailer->configure($setting['email_host'], $setting['email_username'], $setting['email_password'], $setting['email_port'], $setting['is_ssl'], 0);
            $email_resp = $this->Mailer->sendEmail($data);
            $response = !empty($email_resp['status'])?$email_resp['data']:$email_resp['error']; 
            if(!empty($ref_id) || !empty($ref_name) || !empty($user_id)) {
                $from = is_array($this->Mailer->email_from) ? implode(",", $this->Mailer->email_from) : $this->Mailer->email_from;
                $to = implode(",", $this->Mailer->email_to);
                $cc = NULL;
                $attachments = NULL;
                if(!empty($this->Mailer->email_cc)) {
                    $cc = implode(",", $this->Mailer->email_cc);
                }
                if(!empty($data['attachments'])) {
                    $attachments = json_encode($data['attachments']);
                }
                $res = $this->saveClientEmailSmsLog($comp_id, $user_id, 'Email', $data['body'], $data['subject'], $from, $to, $cc, $attachments, $response, $log_id, $ref_id, $ref_name);
                if(!$res['status']) {
                    Logger::error($res['error'], ['File' => __FILE__, 'Line'=>__LINE__]);
                }
            }
            return $email_resp;
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function sendClientMessage($msg_data, $medium) {
        try {
            if(!in_array(strtolower($medium), ['sms', 'whatsapp'])) {
                throw new \Exception("Message medium must be either SMS or WhatsApp or All");
            }
            if(empty($msg_data['url'])) {
                throw new \Exception("$medium API URL is not configured");
            }
            if(empty($msg_data['api_method'])) {
                throw new \Exception("$medium API request method (POST OR GET) is not configured");
            }
            if(empty($msg_data['api_response_type'])) {
                throw new \Exception("$medium API response data type (Text OR JSON) is not configured");
            }
            $callrs = $this->Api->call($msg_data['url'], $msg_data['api_method'], $msg_data['api_headers'], $msg_data['api_data']);
            Logger::debug("call::".strtolower($callrs['status']), ['File' => __FILE__, 'Line'=>__LINE__]);
            if(empty($callrs['status'])) {
                throw new \Exception($callrs['error']);
            }
            if(empty($callrs['data'])) {
                throw new \Exception("No response from SMS/WhatsApp API");
            }
            return ["status"=>true, "data"=>$callrs['data']];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }
} 