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

namespace App\Avanse\Services;

use App\Avanse\DataModels\AvanseAddDocument;
use App\Avanse\DataModels\AvanseApproveMandate;
use App\Avanse\DataModels\AvanseCustomer;
use App\Avanse\DataModels\AvanseDeleteDocument;
use App\Avanse\DataModels\AvanseDisbursementInstruction;
use App\Avanse\DataModels\AvanseFinance;
use App\Avanse\DataModels\AvanseFinCustomStatus;
use App\Avanse\DataModels\AvanseFinOverDueDetails;
use App\Avanse\DataModels\AvanseSearchCustomer;
use App\Avanse\DataModels\AvanseStatement;
use App\Avanse\Logging\Logging;
use App\AvanseEarlySettlement;
use App\AvanseManualPayment;
use App\BulkPayments;
use App\CampaignsJobProvider;
use App\EmiPayment;
use App\PaymentTransaction;
use App\Slack;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class AvanseServices extends Logging {

    public static $lender_id = 3;
    public static $LENDER_NAME = 'Avanse';

    public function getSystemDate(){
        $this->getService = __FUNCTION__;
        return $this->connect();
    }

    public function createCustomer(AvanseCustomer $avanseCustomer){
        $this->getService = __FUNCTION__;
        $this->payload = $avanseCustomer->getPayload();
        if ($avanseCustomer->error){
            return false;
        }
        return $avanseCustomer->saveResponse($avanseCustomer, $this->connect());
    }

    public function createFinance(AvanseFinance $avanseFinance){
        $this->getService = __FUNCTION__;
        $this->payload = $avanseFinance->getPayload();

        if ($avanseFinance->error){
            return false;
        }

        return $avanseFinance->saveResponse($avanseFinance, $this->connect());
    }

    public function updateFinancials(AvanseFinance $avanseFinance){
        $this->getService = __FUNCTION__;
        $avanseFinance->service = $this->getService;
        $this->payload = $avanseFinance->getPayload();

        if ($avanseFinance->error){
            return false;
        }

        return $avanseFinance->saveResponse($avanseFinance, $this->connect(), $this->getService);
    }

    public function callBRE(AvanseFinance $avanseFinance){
        $this->getService = __FUNCTION__;
        $avanseFinance->service = $this->getService;
        $this->payload = $avanseFinance->getPayload();

        if ($avanseFinance->error){
            return false;
        }

        return $avanseFinance->saveResponse($avanseFinance, $this->connect(), $this->getService);
    }

    public function searchCustomer(AvanseSearchCustomer $searchCustomer){
        $this->getService = __FUNCTION__;
        $this->payload = $searchCustomer->getPayload();

        if ($searchCustomer->error){
            return false;
        }

        return $searchCustomer->saveResponse($searchCustomer, $this->connect());
    }

    public function approveMandate(AvanseApproveMandate $avanseApproveMandate){
        $this->getService = __FUNCTION__;
        $this->payload = $avanseApproveMandate->getPayload();

        if ($avanseApproveMandate->error){
            return false;
        }

        return $avanseApproveMandate->saveResponse($avanseApproveMandate, $this->connect());
    }

    public function addFinDocument(AvanseAddDocument $avanseAddDocument){
        $this->getService = __FUNCTION__;
        $this->payload = $avanseAddDocument->getPayload();
        if ($avanseAddDocument->error){
            return false;
        }
        return $avanseAddDocument->saveResponse($avanseAddDocument, $this->connect());
    }

    public function addDocument(AvanseAddDocument $avanseAddDocument){
        $this->getService = __FUNCTION__;
        $avanseAddDocument->getService = __FUNCTION__;
        $this->payload = $avanseAddDocument->getPayload();
        if ($avanseAddDocument->error){
            return false;
        }
        return $avanseAddDocument->saveResponse($avanseAddDocument, $this->connect());
    }

    //For customer document
    public function addCustomerDocument(AvanseAddDocument $avanseAddDocument){
        $this->getService = __FUNCTION__;
        $avanseAddDocument->getService = __FUNCTION__;
        $this->payload = $avanseAddDocument->getPayload();
        if ($avanseAddDocument->error){
            return false;
        }
        return $avanseAddDocument->saveResponse($avanseAddDocument, $this->connect());
    }

    public function getFinCustomStatus(AvanseFinCustomStatus $avanseFinCustomStatus){
        $this->getService = __FUNCTION__;
        $this->payload = $avanseFinCustomStatus->getPayload();
        if ($avanseFinCustomStatus->error){
            return false;
        }
        return $avanseFinCustomStatus->saveResponse($avanseFinCustomStatus, $this->connect());
    }

    public function deleteFinDocument(AvanseDeleteDocument $avanseDeleteDocument){
        $this->getService = __FUNCTION__;
        $this->payload = $avanseDeleteDocument->getPayload();
        if ($avanseDeleteDocument->error){
            return false;
        }
        return $avanseDeleteDocument->saveResponse($avanseDeleteDocument, $this->connect());
    }

    //deleteCustomerDocument
    public function customerService(AvanseDeleteDocument $avanseDeleteDocument){
        $this->getService = __FUNCTION__;
        $avanseDeleteDocument->service = $this->getService;
        $this->payload = $avanseDeleteDocument->getPayload();
        if ($avanseDeleteDocument->error){
            return false;
        }
        return $avanseDeleteDocument->saveResponse($avanseDeleteDocument, $this->connect());
    }

    public function getFinOverDueDetails(AvanseFinOverDueDetails $avanseFinOverDueDetails){
        $this->getService = __FUNCTION__;
        $this->payload = $avanseFinOverDueDetails->getPayload();
        if ($avanseFinOverDueDetails->error){
            return false;
        }
        return $avanseFinOverDueDetails->saveResponse($avanseFinOverDueDetails, $this->connect());
    }

    public function getStatement(AvanseStatement $avanseStatement){
        $this->getService = __FUNCTION__;
        $this->payload = $avanseStatement->getPayload();
        if ($avanseStatement->error){
            return false;
        }
        return $avanseStatement->saveResponse($avanseStatement, $this->connect());
    }

    public function earlySettlement(){
        $this->getService = __FUNCTION__;
        $this->payload = [
            "finReference" => "DELDP00220133",
            "fromDate" => "2022-03-29T09:01:16.329987Z",
            "amount" => "20000",
            "paymentMode" => "NEFT",
            "excessAdjustTo" => "E",
            "reqType" => "Post",
            "receiptDetail" => [
                    "paymentRef" => "CMS1267659760",
                "transactionRef" => "CMS1265659360",
                "fundingAccount" => 4,
                "receivedDate" => "2021-06-20T12:00:00",
                "remarks" => "Loan Cancellation",
            ],
            "fees" => []
        ];
        $this->connect();

        AvanseEarlySettlement::fill([
           'application_id' =>  $this->request->get('id'),
            'response' => json_encode($this->response)
        ]);

        return $this->response->returnStatus->returnText;
    }

    public static function startAvanseProcess(){

    }

    public function nachPayment(){

        $bulkPayments = BulkPayments::with( 'avanseManualPayment', 'finReference')->where('created_at', '>=', $this->request->get('date'))->where('is_available', '>', 0)->whereNotIn('application_id', [181])->get(['id', 'application_id', 'payload']);

        $successCount = 0;
        foreach ($bulkPayments as $payment){

            $payload = json_decode($payment->payload);
            $item = $payload->item;
            if ($item[6] == 'success') {

                if($payment->finReference && (!$payment->avanseManualPayment || (!$payment->avanseManualPayment->status && $payment->avanseManualPayment->attempt < 3))) {

                    $this->request = $this->getManualPaymentPayload($payment, $item);

                    $this->manualPayment(true);
                    $successCount ++;
                }else if ($payment->finReference->finReference && (!$payment->avanseManualPayment->status && $payment->avanseManualPayment->attempt == 3)){
                    $finRefNumbers[] = $payment->finReference->finReference;
                }
            }
        }

        if (isset($finRefNumbers)){
            (new Slack(new Request(['title' => 'LotusPay-Avanse Payment Upload Failed', 'fields' => ['Payment Date' =>$this->request->get('date'), 'Failed Count' => count($finRefNumbers), 'Success Count' => $successCount, 'Reference Nos' => json_encode($finRefNumbers)], 'group' => 'payment_collection'])))->send();
        }
        return true;
    }

    public function getManualPaymentPayload($payment, $item){

        $mode = 'NEFT';
        $bank_code = '';
        if ($this->request->get('payment_mode')){
             if (strtolower($this->request->get('payment_mode')) == 'cash'){
                $mode = 'CASH';
             }else if (strtolower($this->request->get('payment_mode')) == 'cheque'){
                 $mode = 'CHEQUE';

             }
        }

        $receiptDeails = ["fundingAccount" => "5",
            "transactionRef" => $item[3],
            "receivedDate" => date('c', strtotime($item[1])),
            "paymentRef" => $item[3],
            ];

        if ($mode == 'CHEQUE'){
            $receiptDeails['bankCode'] = 'ABHY';
        }

        return new Request(['bulk_id' => $payment->id, 'attempt' => isset($payment->avanseManualPayment->attempt) ? $payment->avanseManualPayment->attempt + 1 : 1, 'application_id' => $item[5], 'data' => [
            "finReference" => $payment->finReference->finReference ?? '',
            "amount" => $item[0],
            "fees" => [],
            "realizationDate" => date('c', strtotime("+1 day", strtotime($item[1]))),
            "paymentMode" => $mode,
            "excessAdjustTo" => "A",
            "reqType" => "Post",
            "receiptDetail" => $receiptDeails,
            "stpProcess" => true
        ]]);
    }

    public function manualPayment($nach = false){
        $this->getService = __FUNCTION__;
        $this->payload = $this->request->get('data');
        $this->response = $this->connect();

        if (!isset($this->response->returnStatus->returnCode) || $this->response->returnStatus->returnCode != '0000'){
            $error = $this->response->returnStatus->returnText ?? 'Failed to send Manual Payment';
        }

        $avanseManualPayment = AvanseManualPayment::where('bulk_id', $this->request->get('bulk_id'))->first(['id']);

        $data = [
            'bulk_id' => $this->request->get('bulk_id'),
            'application_id' => $this->request->get('application_id'),
            'status' => isset($error) ? 0 : 1,
            'message' => $error ?? 'Success',
            'response' => json_encode($this->response),
            'attempt' => $this->request->get('attempt'),
            'created_at' => Carbon::now()->toDateTimeString(),
        ];

        if(isset($avanseManualPayment->id)) {
            AvanseManualPayment::where('id', $avanseManualPayment->id)->update($data);
        }else{
            AvanseManualPayment::insert($data);
        }

        return true;
    }

    public function feePayment(){
        $this->getService = __FUNCTION__;
        return $this->connect();
    }

    public function addDisbursementInstructions(AvanseDisbursementInstruction $avanseDisbursementInstruction){
        $this->getService = __FUNCTION__;
        $this->payload = $avanseDisbursementInstruction->getPayload();

        if ($avanseDisbursementInstruction->error){
            return false;
        }

        return $avanseDisbursementInstruction->saveResponse($avanseDisbursementInstruction, $this->connect());
    }

    public function addDisbursementInstructionsTranches(AvanseDisbursementInstruction $avanseDisbursementInstruction){
        $this->getService = __FUNCTION__;
        $avanseDisbursementInstruction->service = $this->getService;
        $this->payload = $avanseDisbursementInstruction->getPayload();

        if ($avanseDisbursementInstruction->error){
            return false;
        }

        return $avanseDisbursementInstruction->saveResponse($avanseDisbursementInstruction, $this->connect());
    }

    public function getDisbursementInstructions(AvanseDisbursementInstruction $avanseDisbursementInstruction){
        $this->getService = __FUNCTION__;
        $avanseDisbursementInstruction->service = $this->getService;
        $this->payload = $avanseDisbursementInstruction->getPayload();

        if ($avanseDisbursementInstruction->error){
            return false;
        }

        return $avanseDisbursementInstruction->saveResponse($avanseDisbursementInstruction, $this->connect());
    }

    public function getForeclosureLetter(){
        $this->getService = __FUNCTION__;
        $this->payload = [
            "finReference"=>$this->request->get('finReference'),
            "days"=>$this->request->get('days')
        ];
        return $this->connect();
    }

    public function initializeRituals($payload, $func) {
        $this->initialize();
        $this->payload = $payload;
        $avanse = \Config::get('avanse');
        return $avanse['services'][$func];
    }

    public function getPaymentLink($headers, $payload) {
        $this->getService = __FUNCTION__;
        $service = $this->initializeRituals($payload, __FUNCTION__);
        $this->paymentConnect($service, $payload, $headers);
        return json_decode($this->response, 1);
    }

    public function getPaymentStatus($headers, $payload) {
        $this->getService = __FUNCTION__;
        $service = $this->initializeRituals($payload, __FUNCTION__);
        $this->paymentConnect($service, $payload, $headers);
        return json_decode($this->response, 1);
    }

    public function paymentConnect($service, $payload, $headers) {
        $this->sendRequest($service['URL'].$service['API'], $service['Method'], json_encode($payload), $headers);
    }

    public static function getDocumentsLists(){
        $documents = DB::connection('avanse')->table('BMTDocumentTypes')->get();
        $lists = [];
        foreach ($documents as $document){
            if($document->DocTypeDesc) {
                $lists[] = ['docName' => $document->DocTypeDesc, 'code' => $document->DocTypeCode, 'name' => 0, 'password' => 0, 'bank' => 0];
            }
        }
        return $lists;
    }

    private function sendRequest($url, $method, $payload, $headers = []) {

        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_POSTFIELDS => $payload,
            CURLOPT_HTTPHEADER => $headers,
        ));

        $this->response = curl_exec($curl);

        if(1 == _env("AVANSE_LOG")) {
            $this->logging();
        }
        curl_close($curl);
    }

    private function connect(){
        $this->initialize();

        if(empty($this->headers)) {
            $this->headers = array(
                'Content-Type: application/json',
                'Accept: application/json',
                'Authorization: '.$this->service['Authorization'],
                'MessageId: '.$this->messageID,
                'ServiceVersion: '.$this->serviceAttributes['ServiceVersion'],
                'SERVICENAME: '.$this->service['ServiceName'],
                'LANGUAGE: '.$this->serviceAttributes['LANGUAGE'],
                'entityid: '.$this->serviceAttributes['entityID'],
                'REQUESTTIME: '.date("c", time())
            );
        }
        $this->sendRequest($this->api, $this->service['Method'], json_encode($this->payload), $this->headers);
        return json_decode($this->response);
    }
}
