<?php

namespace App\Http\Controllers;

use App\ConsumerApplication;
use App\ConsumerApplicationElement;
use App\Http\Controllers\Admin\ConsumerDocument;
use App\Merchant;
use App\Slack;
use App\Templates;
use App\User;
use App\WhatsApp;
use App\WhatsappCustomerService;
use App\WhatsappMessages;
use Carbon\Carbon;
use Google\ApiCore\ValidationException;
use Google\Cloud\Dialogflow\V2\QueryInput;
use Google\Cloud\Dialogflow\V2\SessionsClient;
use Google\Cloud\Dialogflow\V2\TextInput;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;


/*{
    "id": "ac160002-7440-116b-8174-a4fb39ae38e6",
    "url": "https://creditfair.in/api/communication-input",
    "challengeToken": "AY6SKsbuRNTsFHD3SBFg2JhzS1zbv3XMMr2iETc3",
    "events": [
        "message:user:in"
    ],
    "active": true
}
*/

define('KABOOTAR_INPUT', 'message:user:in');
define('KABOOTAR_CHALLENGE_TOKEN', 'AY6SKsbuRNTsFHD3SBFg2JhzS1zbv3XMMr2iETc3');
define('KABOOTAR_STOP', 'stop');
define('KABOOTAR_SERVICE_NAME', 'KABOOTAR');
define('KABOOTAR_SERVICE_VERSION', '1');

class Kabootar extends Controller
{
    private static $SPECIFY_DOCUMENT = 'specify_document';
    private static $DOCUMENT_UPLOADED = 'document_uploaded';

    private static $BINARY = 'BINARY';
    private $request;
    private $projectID = 'creditfair-hogwbj';
    private $lang = 'en-US';
    private $communicationOutputData = [];
    private $communicationInputData;
    private $session = null;
    private $platformSenderId;
    private $init = false;
    private $documentMapping = [1 => 'nach', 2 => 'security_cheques', 3 => 'utility_bill', 4 => 'other'];
    private $templateTypeSystem = false;
    private $binaryResponse;
    private $application = null;
    private $documentMappingStatus = ['approved'];

    public function __construct(Request $request){
        $this->request = $request;
        $this->updateRequest();
        $this->getSession();
    }

    //dialogFlow
    public function communicationOutput(){

        $this->messageBagKabootar(KABOOTAR_SERVICE_NAME.' '.__FUNCTION__, $this->request->input());
    }

    public function communicationInput(){
        try {
            if ($this->init && $this->request->has('event') && $this->request->get('event') == KABOOTAR_INPUT) {
                if ($this->getAppDirections()) {
                    if ($this->shouldConnectToDialogFlow()) {
                        $this->connectToDialogFlow();
                    }
                }
                $this->dispatchKabootar();
            }
        }catch (\Exception $e){
            $this->messageBagKabootar(KABOOTAR_SERVICE_NAME . ' ' . __FUNCTION__, [
                'Message' => $e->getMessage(),
                'Line' => $e->getLine(),
                'File' => $e->getFile()
            ]);
        }

        $this->serviceLogs();
        return response()->json(['status' => 'OK'], 200);
    }

    public function whatsappCustomerService(){
        $user_type = 'consumer';
        $application = ConsumerApplication::with('advisor')->where('mobile_number', $this->platformSenderId)->orderBy('created_at','desc')->first(['id','created_at','name','merchant_id', 'created_by']);
        $CoApplicantApplication = ConsumerApplication::where('co_applicant_mobile_number', $this->platformSenderId)->orderBy('created_at','desc')->first(['id','created_at','co_applicant_name as name']);

        if (!isset($application->id)){
            $application = $CoApplicantApplication;
        }

        if (isset($application->id)) {

            if (isset($CoApplicantApplication->id)){
                if(strtotime($application->created_at) < strtotime($CoApplicantApplication->created_at)){
                    $application = $CoApplicantApplication;
                }
            }
            if (in_array($this->request->get('text'), ['Not Satisfactory','बुरी'])){
                $merchant = Merchant::where('id', $application->merchant_id)->first(['merchant_name']);
                $advisor_id = isset($application->advisor) && isset($application->advisor->id) ? $application->advisor->id : '';
                (new Slack(new Request(['title' => 'Review received from '.strtolower($application->name), 'fields' => ['Merchant Name' =>$merchant->merchant_name, 'Source' => 'WhatsApp', 'Application Id' => $application->id, 'Review' => $this->request->get('text')],'group' => Slack::$merchant_customer_review, 'tagging' => [$advisor_id]])))->send();
            }
        }else{
            $application = Merchant::where('contact_number', $this->platformSenderId)->orderBy('created_at','desc')->first(['id','created_at','merchant_name']);
            $user_type = 'merchant';

            if (in_array($this->request->get('text'), ['Not Satisfactory','बुरी'])){
                (new Slack(new Request(['title' => 'Review received from '.strtolower($application->merchant_name), 'fields' => ['Merchant Name' =>$application->merchant_name, 'Source' => 'WhatsApp', 'Merchant Id' => $application->id, 'Review' => $this->request->get('text')],'group' => Slack::$merchant_customer_review])))->send();
            }
        }


        WhatsappCustomerService::insert([
            'application_id' => $application->id,
            'request_id' => $this->request->get('id'),
            'type' => Templates::$rate_service_v1,
            'user_type' => $user_type,
            'payload' => $this->request->get('text'),
            'created_at' => Carbon::now()->toDateTimeString()
        ]);
    }

    public function shouldConnectToDialogFlow(){
        if($this->request->has('context')){
            $parentId = $this->request->get('context')['parentId'];
            $whatsappMessages = WhatsappMessages::where('request_id',trim($parentId))->first();
            if (isset($whatsappMessages->id) && $whatsappMessages->message == 'rate_service_v1' && !$whatsappMessages->output_message) {
                WhatsappMessages::where('request_id', $parentId)->update(['output_message' => $this->request->get('text')]);
                $this->whatsappCustomerService();
                $this->communicationOutputData['fulfilmentText'] = in_array($this->request->get('text'), ['Excellent','बहुत अच्छी']) ? 'Thank you for your valuable feedback. We would appreciate if you could rate us on google too https://tinyurl.com/32769uze' : $this->sendProblemFaced();
                return false;
            }elseif (isset($whatsappMessages->id) && $whatsappMessages->message == 'issue_faced_service' && !$whatsappMessages->output_message) {
                WhatsappMessages::where('request_id', $parentId)->update(['output_message' => $this->request->get('text')]);
                $this->whatsappCustomerService();
                $this->sendProblemYesNoFaced();
                return false;
            }elseif (isset($whatsappMessages->id) && $whatsappMessages->message == 'issue_faced_service_sec' && !$whatsappMessages->output_message) {
                WhatsappMessages::where('request_id', $parentId)->update(['output_message' => $this->request->get('text')]);
                $this->whatsappCustomerService();
                $this->communicationOutputData['fulfilmentText'] = $this->request->get('text') == 'No' ? 'We have received your feedback' : $this->sendProblemYesNoAfterFaced();
                return false;
            }elseif (isset($whatsappMessages->id) && $whatsappMessages->message == 'issue_faced_service_thr' && !$whatsappMessages->output_message) {
                WhatsappMessages::where('request_id', $parentId)->update(['output_message' => $this->request->get('text')]);
                $this->whatsappCustomerService();
                $this->communicationOutputData['fulfilmentText'] = $this->sendProblemYesNoAfterFacedResponse();
                return false;
            }else{
                $this->communicationOutputData['fulfilmentText'] = 'We already received your feedback';
            }
        }else{
            $this->getLastCommunication();
        }
        return false;
    }

    public function getLastCommunication(){
        $whatsappMessages = WhatsappMessages::whereIn('platformSenderId',[$this->request->get('platformSenderId'), str_replace('+','',$this->request->get('platformSenderId'))])->where('type','message:store:system:out')->orderBy('created_at','desc')->first();
        if ($this->application && isset($whatsappMessages->id) && in_array($this->application->state, $this->documentMappingStatus)){
            switch ($whatsappMessages->message){
                case 'document_message_bot':
                case static::$SPECIFY_DOCUMENT;
                case static::$DOCUMENT_UPLOADED;

                    if(!$this->shouldRun())
                        return false;

                    if (in_array($this->request->get('text'), array_keys($this->documentMapping))){
                        if ($this->request->get('text') == 4){
                            $this->communicationOutputData['fulfilmentText'] = 'Please specify document name';
                            $this->templateTypeSystem = $this->getPayload(['templateId' => static::$SPECIFY_DOCUMENT, 'templateType' => 'text', 'to' => $this->request->get('platformSenderId')]);
                        }else{
                            $this->communicationOutputData['fulfilmentText'] = 'Please send the '.ucfirst(str_replace('_','',$this->documentMapping[$this->request->get('text')])).' document';
                        }
                    }else if($this->binaryResponse && $this->application){
                        if($this->uploadDocument()) {
                            $this->templateTypeSystem = $this->getPayload(['templateId' => static::$DOCUMENT_UPLOADED, 'templateType' => 'text', 'to' => $this->request->get('platformSenderId')]);
                            $this->communicationOutputData['fulfilmentText'] = 'Document uploaded successfully';
                        }
                    }else if ($whatsappMessages->message == static::$SPECIFY_DOCUMENT){
                        $this->communicationOutputData['fulfilmentText'] = 'Please send the '.ucfirst(str_replace('_','',$this->request->get('text')));
                    }
                    break;
            }
        }
    }

    public function shouldRun(){
        $whatsappMessages = WhatsappMessages::whereIn('platformSenderId',[$this->request->get('platformSenderId'), str_replace('+','',$this->request->get('platformSenderId'))])->where('message','document_message_bot')->where('type','message:store:system:out')->orderBy('created_at','desc')->first();
        if($whatsappMessages->message == 'document_message_bot'){
            if(Carbon::now()->timestamp < Carbon::parse($whatsappMessages->created_at)->addDays(2)->timestamp){
                return true;
            }
        }else{
            if(Carbon::now()->timestamp < Carbon::parse($whatsappMessages->created_at)->addDays(2)->timestamp){
                return true;
            }
        }

        return false;
    }

    public function uploadDocument(){
        $extension = explode('.',$this->request->get('fileUrl'));
        if($name = $this->getFileName()) {
            (new ConsumerDocument(new Request()))->uploadToS3($name, $this->application->id, file_get_contents($this->request->get('fileUrl')), '.' . $extension[count($extension)-1]);
            $merchant_name = $this->application->merchant ? $this->application->merchant->merchant_name : '';
            $advisor_id = isset($this->application->advisor) && isset($this->application->advisor->id) ? $this->application->advisor->id : '';
            (new Slack(new Request(['title' => $name.' sent on whatsapp uploaded to admin panel.', 'fields' => ['Name' => $this->application->name, 'Merchant Name' => $merchant_name, 'Application ID' => $this->application->id],'group' => 'customer_documents', 'tagging' => [$advisor_id]])))->send();
            return true;
        }
        return false;
    }

    public function getFileName(){
        $whatsappMessages = WhatsappMessages::where('platformSenderId',$this->request->get('platformSenderId'))->where('type','message:user:in')->orderBy('created_at','desc')->first(['id','message']);
        if (isset($whatsappMessages->message) && strpos($whatsappMessages->message, static::$BINARY) === false && in_array($whatsappMessages->message, array_keys($this->documentMapping))){
            if ($whatsappMessages->message == 4){
                return false;
            }
            return isset($whatsappMessages->message) ? $this->documentMapping[$whatsappMessages->message] : false;
        }

        return isset($whatsappMessages->message) && strpos($whatsappMessages->message, static::$BINARY) === false && !is_numeric($whatsappMessages->message) ? $whatsappMessages->message : false;
    }

    public function getPayload($message){
        return [
            'templateId' => isset($message['templateId']) ? $message['templateId'] : '',
            'templateArgs' => isset($message['args']) ? $message['args'] : '',
            'templateType' => isset($message['templateType']) ? $message['templateType'] : '',
            'message_type' => isset($message['type']) ? $message['type'] : '',
            'to' => $message['to']
        ];
    }

    public function getAppDirections(){
        if ($this->session && $this->request->has('text') && strtolower($this->request->get('text')) == KABOOTAR_STOP){
            if($this->isServiceActivated()){
                $this->stopService();
                return false;
            }
        }

        if ($this->isServiceActivated()){
            return true;
        }

        return false;
    }

    public function getSession(){
        try {
            $this->platformSenderId = strlen($this->request->get('platformSenderId')) > 10 ? substr($this->request->get('platformSenderId'), strlen($this->request->get('platformSenderId')) - 10) : $this->request->get('platformSenderId');
            if (strlen($this->platformSenderId) > 10) {
                $this->platformSenderId = substr($this->platformSenderId, 2);
            }

            $this->session = User::where('mobile_number', $this->platformSenderId)->first(['whatsapp_api', 'user_verified', 'id']);
            $this->init = $this->session && $this->session->whatsapp_api ? $this->session->whatsapp_api : false;
            if(!$this->init){
                $this->init = $this->session && is_null($this->session->whatsapp_api) && $this->session->user_verified ? true : false;
            }
            if($this->session) {
                $application = ConsumerApplication::with('merchant', 'advisor')->where('user_id', $this->session->id)->orderBy('created_at','desc')->first(['id', 'merchant_id', 'name', 'state']);
                if (isset($application->id)){
                    $this->application = $application;
                }else{
                    $application = ConsumerApplication::with('merchant', 'advisor')->where('mobile_number', $this->platformSenderId)->orderBy('created_at','desc')->first(['id' ,'merchant_id' ,'name' ,'state']);
                    if (isset($application->id)){
                        $this->application = $application;
                    }
                }

                Auth::login($this->session);
            }
        }catch (\Exception $e) {
            $this->messageBagKabootar(KABOOTAR_SERVICE_NAME.' '.__FUNCTION__, [
                'Message' => $e->getMessage(),
                'Line' => $e->getLine(),
                'File' =>$e->getFile()
            ]);
        }
    }

    private function updateRequest(){
        if(!$this->request->get('platformSenderId')){
            $this->request = new Request(json_decode(file_get_contents("php://input"), 1));
        }

        $this->binaryResponse = $this->request->has('fileUrl');
    }

    public function stopService(){
        User::where('id',$this->session->id)->update(['whatsapp_api' => 0]);
        $this->communicationOutputData['fulfilmentText'] = 'Service Stopped! We won\'t send any communication to you';
    }

    public function isServiceActivated(){
        if($this->session && is_null($this->session->whatsapp_api)){
            if($this->session->user_verified){
                User::where('id',$this->session->id)->update(['whatsapp_api' => 1]);
                return true;
            }
        }
        return $this->session ? $this->session->whatsapp_api : null;
    }

    public function dispatchKabootar(){
        $fetchResponse = $this->connectToInputService();
        $this->communicationInputData = $fetchResponse;
    }

    public function connectToInputService(){

        if(isset($this->communicationOutputData['fulfilmentText']) && $this->communicationOutputData['fulfilmentText'] && $this->request->get('platformSenderId')) {
            $request = new Request([
                'templateId' => '',
                'templateArgs' => array(),
                'templateType' => 'text',
                'messageString' => $this->communicationOutputData['fulfilmentText'],
                'to' => $this->request->get('platformSenderId'),
                'templateTypeSystem' => $this->templateTypeSystem
            ]);

            $whatsApp = new WhatsApp($request);
            return $whatsApp->sendMessage();
        }
        return false;
    }

    /**
     * Returns the result of detect intent with texts as inputs.
     * Using the same `session_id` between requests allows continuation
     * of the conversation.
     * @throws \Google\ApiCore\ApiException
     */

    public function connectToDialogFlow(){
        // new session
        try {
            $sessionsClient = new SessionsClient();
            $session = $sessionsClient->sessionName($this->projectID, $this->request->get('platformSenderId') ?: uniqid());
            $this->communicationOutputData['session'] = $session;

            // query for each string in array
            $textInput = new TextInput();
            $textInput->setText($this->request->get('Text'));
            $textInput->setLanguageCode($this->lang);

            // create query input
            $queryInput = new QueryInput();
            $queryInput->setText($textInput);

            // get response and relevant info
            $response = $sessionsClient->detectIntent($session, $queryInput);
            $queryResult = $response->getQueryResult();
            $queryText = $queryResult->getQueryText();
            $intent = $queryResult->getIntent();
            $displayName = $intent->getDisplayName();
            $confidence = $queryResult->getIntentDetectionConfidence();
            $fulfilmentText = $queryResult->getFulfillmentText();

            // output relevant info
            $this->communicationOutputData['queryText'] = $queryText;
            $this->communicationOutputData['displayName'] = $displayName;
            $this->communicationOutputData['confidence'] = $confidence;
            $this->communicationOutputData['fulfilmentText'] = $fulfilmentText;

            $sessionsClient->close();
        } catch (ValidationException $e) {

        }
    }

    public function messageBagKabootar($title, $bag){
        (new Slack(new Request(['title' => $title, 'fields' => $bag, 'group' => Slack::$CHAT_BOT])))->send();
    }

    private function serviceLogs(){
        WhatsappMessages::insert(
            [
                'request_id' => $this->request->get('id'),
                'platformSenderId' => $this->request->get('platformSenderId'),
                'message' => $this->request->has('fileUrl') ? 'BINARY|'.$this->request->get('type') : $this->request->get('text'),
                'payload' => json_encode($this->request->input()),
                'type' => $this->request->get('event'),
                'created_at' => Carbon::now()->toDateTimeString()
            ]
        );
    }

    public function sendProblemFaced(){
        if(in_array($this->request->get('text'), ['Not Satisfactory','बुरी']) &&  $this->application){
            $args = ['P-NACH/E-NACH', 'ESign Loan Agreement', 'Merchant Service'];

            $element = ConsumerApplicationElement::where('application_id', $this->application->id)->whereIn('preferred_language', ['HINDI','MARATHI'])->first(['id']);

            $templateLanguage = isset($element->id) ? 'hi' : 'en';
            sendWhatsAppMessage($this->request->get('platformSenderId'), ['id' => $this->application->id, 'templateId' => Templates::$issue_faced_service, 'args' => $args, 'templateType' => 'buttonTemplate', 'templateLanguage' => $templateLanguage]);
            return '';
        }
        return 'We have received your feedback';
    }

    public function sendProblemYesNoFaced(){
        $args = ['Yes','No'];

        $element = ConsumerApplicationElement::where('application_id', $this->application->id)->whereIn('preferred_language', ['HINDI','MARATHI'])->first(['id']);

        $templateLanguage = isset($element->id) ? 'hi' : 'en';
        sendWhatsAppMessage($this->request->get('platformSenderId'), ['id' => $this->application->id, 'templateId' => Templates::$issue_faced_service_sec, 'args' => $args, 'templateType' => 'buttonTemplate', 'templateLanguage' => $templateLanguage]);
        return '';
    }

    public function sendProblemYesNoAfterFaced(){
        $args = ['Advisor Behaviour','Additional Documents'];

        $element = ConsumerApplicationElement::where('application_id', $this->application->id)->whereIn('preferred_language', ['HINDI','MARATHI'])->first(['id']);

        $templateLanguage = isset($element->id) ? 'hi' : 'en';
        sendWhatsAppMessage($this->request->get('platformSenderId'), ['id' => $this->application->id, 'templateId' => Templates::$issue_faced_service_thr, 'args' => $args, 'templateType' => 'buttonTemplate', 'templateLanguage' => $templateLanguage]);
        return '';
    }

    public function sendProblemYesNoAfterFacedResponse(){

        $element = ConsumerApplicationElement::where('application_id', $this->application->id)->whereIn('preferred_language', ['HINDI','MARATHI'])->first(['id']);

        return $templateLanguage = isset($element->id) ? 'प्रतिक्रिया के लिए धन्यवाद हमारे सलाहकार जल्द ही आपकी सहायता करेंगे' : 'Thank you for the response our advisor will soon assist you';
    }
}
