<?php
/**
 * Created by PhpStorm.
 * User: sunilkhorwal
 * Date: 2019-05-30
 * Time: 15:57
 */

namespace App\Exotel;


use App\CallLogs;
use App\ConsumerApplication;
use App\ConsumerApplicationFiles;
use App\Http\Controllers\Admin\ConsumerDocument;
use App\Logging\CloudWatchLoggerFactory;
use App\Slack;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;

class Exotel{

    private $request;
    private $callType = 'trans';
    private $exotelVirtualNumber;
    private $exotel_api_key;
    private $exotel_sid;
    private $exotel_token;
    private $requestData = array();
    private $endPoint;
    private $method;
    private $statusCallback = 'https://creditfair.in/exotel/init';
    private $isDelete = false;
    private $callReInitiated = false;
    private $paymentPurpose = ['nach_followup','payment_collection','overdue_emi','emi_reminder'];
    public $autoInitiateGetCall = false;

    public function __construct(Request $request){
        $this->request = $request;
        $this->callType = $request->has('callType') ? $request->get('callType') : $this->callType;

        $this->exotelVirtualNumber = $this->getVirtualNumber();
        $this->exotel_api_key = _env('EXOTEL_API_KEY');
        $this->exotel_sid = _env('EXOTEL_SID');
        $this->exotel_token = _env('EXOTEL_TOKEN');
        $this->method = 'true';
    }

    public function initiateCall(){

        if ($this->request->get('to')) {
            $this->requestData = array(
                'From' => strlen($this->request->get('from')) == 10 ? $this->request->get('from') : '91' . $this->request->get('from'),
                'To' => strlen($this->request->get('to')) == 10 ? $this->request->get('to') : '91' . $this->request->get('to'),
                'CallerId' => $this->exotelVirtualNumber,
                'CallType' => $this->callType,
                'StatusCallback' => $this->statusCallback,
                'StatusCallbackContentType' => 'application/json',
                'StatusCallbackEvents' => array('terminal'),
                'Record' => 'true'
            );

            $this->endPoint = "https://" . $this->exotel_api_key . ":" . $this->exotel_token . "@twilix.exotel.in/v1/Accounts/" . $this->exotel_sid . "/Calls/connect";

            $connects = $this->connect();

            $responseString = simplexml_load_string($connects['http_result']);
            $call = $responseString->Call;
            $status=$call->status;
            $response = $this->parseResponse(['code' => $connects['http_code'], 'data' => $responseString, 'error' => $connects['error'], 'call' => $call,'status'=>$status]);
            $this->saveResponse($response);
            $data = $response->getData();
            if (isset($data->message) && $data->message == 'DND') {
                if ($this->makeNumberWhiteList()) {
                    $this->callReInitiated = true;
                    return $this->initiateCall();
                }
            }

            return $response;
        }
    }

    public function connect(){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_VERBOSE, 1);
        curl_setopt($ch, CURLOPT_URL, $this->endPoint);
        curl_setopt($ch, CURLOPT_POST, $this->method);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_FAILONERROR, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        if ($this->method)
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($this->requestData));

        if ($this->isDelete)
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->isDelete);
        $http_result = curl_exec($ch);
        $error = curl_error($ch);
        $http_code = curl_getinfo($ch ,CURLINFO_HTTP_CODE);

        curl_close($ch);

        //(new \App\Slack(new \Illuminate\Http\Request(['title'=>'Exotel Error Error','fields'=>['param' => http_build_query($this->requestData), 'error'=> json_encode($this->requestData), 'data' => json_encode(['http_result' => $http_result, 'error' => $error, 'http_code' => $http_code])],  'group' => Slack::$STAGE_TESTING])))->send();
        return ['http_result' => $http_result, 'error' => $error, 'http_code' => $http_code];
    }

    public function initiateGetCall(){
        $this->method = false;
        $this->endPoint = "https://".$this->exotel_api_key.":".$this->exotel_token."@twilix.exotel.in/v1/Accounts/".$this->exotel_sid."/Calls/".$this->request->get('sid');

        $connects = $this->connect();

        $responseString = simplexml_load_string($connects['http_result']);
        $cwFactory = new CloudWatchLoggerFactory();
        $_data = array(
            'application_id'=>$this->request->get('id'),
            'response' => json_encode($responseString),
        );
        $cwFactory->logger(json_encode($_data));
        if ($this->autoInitiateGetCall)
            return $this->getResponse($responseString);
        if ($this->request->has('id')){
            $_data = array(
                'application_id'=>$this->request->get('id'),
                'message' => 'saveRecording',
            );
            $cwFactory->logger(json_encode($_data));
            $this->saveRecording($responseString);
        }
        return $responseString;

    }

    private function makeNumberWhiteList(){

        $number = strlen($this->request->get('to')) == 10 ? $this->request->get('to') : '91'.$this->request->get('to');
        if ($this->callReInitiated)
            $number = strlen($this->request->get('from')) == 10 ? $this->request->get('from') : '91'.$this->request->get('from');

        $this->requestData = array(
            'VirtualNumber' => $this->exotelVirtualNumber,
            'Number' => $number
        );

        $this->endPoint = "https://".$this->exotel_api_key.":".$this->exotel_token."@twilix.exotel.in/v1/Accounts/".$this->exotel_sid."/CustomerWhitelist";

        $connects = $this->connect();

        $responseString = simplexml_load_string($connects['http_result']);
        return isset($responseString->Result->Succeeded) ? $responseString->Result->Succeeded : false;
    }

    private function removeNumberWhiteList(){

        $this->isDelete = 'DELETE';

        $phone = strlen($this->request->get('to')) == 10 ? $this->request->get('to') : '91'.$this->request->get('to');
        $this->endPoint = "https://".$this->exotel_api_key.":".$this->exotel_token."@twilix.exotel.in/v1/Accounts/".$this->exotel_sid."/CustomerWhitelist?Number=".$phone;

        $connects = $this->connect();

        $responseString = simplexml_load_string($connects['http_result']);
        return isset($responseString->Result->Succeeded) ? $responseString->Result->Succeeded : false;
    }

    public function getResponse($responseString){
        $recordingUrl = isset($responseString->Call->RecordingUrl) ? $responseString->Call->RecordingUrl : '';
        $direction = isset($responseString->Call->Direction) ? $responseString->Call->Direction : '';
        $Status = isset($responseString->Call->Status) ? $responseString->Call->Status : '';
        $StartTime = isset($responseString->Call->StartTime) ? $responseString->Call->StartTime : null;
        $EndTime = isset($responseString->Call->EndTime) ? $responseString->Call->EndTime : null;
        $Duration = isset($responseString->Call->Duration) ? $responseString->Call->Duration : '';

        if (isset($responseString->RestException)){
            $Status = isset($responseString->RestException->Status) ? $responseString->RestException->Status : '';
        }

        return [
            'recordingUrl' => $recordingUrl, 'direction' => $direction, 'Status' => $Status, 'StartTime' => $StartTime, 'EndTime' => $EndTime, 'Duration' => $Duration, 'response' => $responseString
        ];
    }

    public function saveRecording($responseString){

        $data = $this->getResponse($responseString);

        $callLogs = CallLogs::find($this->request->get('id'));
        $callLogs->recording = $data['recordingUrl'];
        $callLogs->direction = $data['direction'];
        $callLogs->status = $data['Status'];
        $callLogs->startTime = $data['StartTime'];
        $callLogs->endTime = $data['EndTime'];
        $callLogs->duration = $data['Duration'];
        $callLogs->save();

        $callLogs = json_decode($callLogs);
        $id_type = $callLogs->id_type ?? '';
        $_id = $callLogs->_id ?? '';

        $cwFactory = new CloudWatchLoggerFactory();
        $_data = array(
            'application_id'=>$_id,
            'call_log' => $callLogs,
            'recordingUrl' => $data['recordingUrl'],
            'id_type' => $id_type,
            '_id' => $this->request->get('id')
        );
        $cwFactory->logger(json_encode($_data));

        try{
            $s3RecordingPath = $this->saveToS3($callLogs, $_data['recordingUrl']);

            if ($s3RecordingPath) {
                
                $_callLogs = CallLogs::find($this->request->get('id'));
                $_callLogs->recording = $s3RecordingPath;
                $_callLogs->save();

                if($id_type != "" && $id_type == "application_id" && $_id != "") {
                    $applicationContacts = ConsumerApplication::with(['application_element' => function ($query) {
                        $query->select('application_id','reference_contact_1', 'reference_contact_2');
                    }])->where('id', $_id)->first(['id', 'mobile_number', 'co_applicant_mobile_number']);

                    $purpose = $data['purpose'] ?? '';
                    $date = $data['created_at'] ?? '';
                    $recipient = $data['to'] ?? '';

                    $callType = 'call_recording';

                    if ($applicationContacts->mobile_number && $applicationContacts->mobile_number == $recipient) {
                        $callType = $purpose . '_' . $date . '_applicant';
                    } elseif ($applicationContacts->co_applicant_mobile_number && $applicationContacts->co_applicant_mobile_number == $recipient) {
                        $callType = $purpose . '_' . $date . '_co_applicant';
                    } elseif ($applicationContacts->application_element->reference_contact_1 && $applicationContacts->application_element->reference_contact_1 == $recipient) {
                        $callType = $purpose . '_' . $date . '_reference_1';
                    } elseif ($applicationContacts->application_element->reference_contact_2 && $applicationContacts->application_element->reference_contact_2 == $recipient) {
                        $callType = $purpose . '_' . $date . '_reference_2';
                    }

                    ConsumerApplicationFiles::insert([
                        'consumer_application_id' => $_id,
                        'file_type' => $callType,
                        'file_path' => $s3RecordingPath,
                        'created_at' => Carbon::now()->toDateTimeString(),
                        'created_by' => 107,
                        'electricity_bill_owner' => 0,
                    ]);
                }
            } else {
                 $cwFactory->logger(json_encode(['message' => 'Skipped 0 byte recording', 'id' => $_id]));
            }
        }catch(\Exception $e){
            $cwFactory = new CloudWatchLoggerFactory();
            $_data = array(
                'application_id'=>$_id,
                'user_id'=> isset(Auth::user()->id)? Auth::user()->id : '',
                'vendor'=> 'exotel',
                'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()
            );
            $cwFactory->logger(json_encode($_data));
        }
    }

    public function saveToS3($callLogs, $recordingUrl){
        try {
            $s3 = Storage::disk('s3');
            $path = '';
            $timestamp = Carbon::now()->timestamp;

            if ($callLogs->id_type == 'application_id') {
                $path = $callLogs->_id . '/call_recoding_' . $callLogs->purpose . '_' . $timestamp . '.mp3';
            } else if ($callLogs->id_type == 'lead_id') {
                $path = '/lead/' . $callLogs->_id . '/call_recoding_' . $callLogs->purpose . '_' . $timestamp . '.mp3';
            } else if ($callLogs->id_type == 'merchant_id') {
                $path = '/merchant/' . $callLogs->_id . '/call_recoding_' . $callLogs->purpose . '_' . $timestamp . '.mp3';
            } else if ($callLogs->id_type == 'merchant_location_id') {
                $path = '/merchant_location/' . $callLogs->_id . '/call_recoding_' . $callLogs->purpose . '_' . $timestamp . '.mp3';
            }

            $curl = curl_init();

            $exotel_user = _env('EXOTEL_API_KEY_USERNAME'); //API KEY(username)
            $exotel_pswd = _env('EXOTEL_API_KEY_PASSWORD'); //API KEY(Password)

            curl_setopt_array($curl, array(
                CURLOPT_URL => $recordingUrl,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_ENCODING => '',
                CURLOPT_MAXREDIRS => 10,
                CURLOPT_TIMEOUT => 0,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
                CURLOPT_CUSTOMREQUEST => 'GET',
                CURLOPT_HTTPHEADER => array(
                    'Authorization: Basic '.base64_encode($exotel_user.':'.$exotel_pswd)
                ),
            ));

            $response = curl_exec($curl);
            $recordingFile = storage_path('/temp-file.mp3');
            file_put_contents($recordingFile, $response);     // Save the MP3 file to disk

            curl_close($curl);
            if (file_exists($recordingFile) && filesize($recordingFile) < 50) {
                unlink($recordingFile); 
                return false;
            }

            if(isset($path) && $path != '' && $recordingUrl != null) {
                $s3->put($path, file_get_contents($recordingFile));

            }

            if(isset($recordingFile)&& file_exists($recordingFile)){
                unlink($recordingFile);
            }
            return $path;

        }catch(\Exception $e){
            $cwFactory = new CloudWatchLoggerFactory();
            $data = array(
                'application_id'=>$callLogs->_id,
                'user_id'=> isset(Auth::user()->id)? Auth::user()->id : '',
                'vendor'=> 'exotel',
                'message' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString()
            );
            $cwFactory->logger(json_encode($data));
        }
    }

    private function saveResponse($response){

        $data = $response->getData();
        $message = isset($data->message) ? $data->message : '';
        $error = isset($data->error) ? $data->error : '';
        $responseData = isset($data->response) ? $data->response : '';
        $sid = isset($responseData->call->Sid) ? $responseData->call->Sid : '';

        CallLogs::insert([
            'user_id' => Auth::user() ? Auth::user()->id : $this->request->get('user_id'),
            '_id' => $this->request->get('id'),
            'id_type' => $this->request->get('application_type'),
            'to' => $this->request->get('to'),
            'from' => $this->request->get('from'),
            'message' => $message,
            'error' => $error,
            'purpose' => $this->request->get('purpose'),
            'description' => json_encode($responseData),
            'sid' => $sid,
            'created_at' => Carbon::now()->toDateTimeString()
        ]);
    }

    private function parseResponse($data){
        if(isset($data['status'])&& $data['status']==429){
            return response()->json(['message'=>'Too many requests, you are calling our API more frequently than we allow.','response'=>$data,'error'=>$data['error'],],200);
        }
        else if($data['code'] == 403){
            return response()->json([
                'message' => 'DND',
                'error' => $data['error'],
                'response' => $data
            ], 200);
        }else if ($data['code'] == 400){
            return response()->json([
                'message' => 'Number you have entered is invalid'
            ], 200);
        }else if ($data['code'] == 200){
            return response()->json([
                'message' => 'Your call is connecting',
                'response'=>$data,
                'error' => $data['error'],
            ], 200);
        }else {
            return response()->json([
                'message' => 'Something went wrong.',
                'error'=>$data
            ], 200);
        }
    }

    private function getVirtualNumber(){
        $userID = Auth::user() ? Auth::user()->id : $this->request->get('user_id');
        if($this->request->get('application_type') == 'lead_id'){
            return '02248970787';
        }
        return $userID && (in_array($userID, [543, 251]) || in_array($this->request->get('purpose'), $this->paymentPurpose)) ? '02248970536' : '02248974752';
    }
}
