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

namespace App\Avanse\DataModels;

use App\Avanse\Processes\AvanseProcesses;
use App\AvanseCreateCustomer;
use App\AvanseCreateFinance;
use App\AvanseDisbursement;
use App\AvanseDisbursementStatus;
use App\ConsumerApplication;
use App\ConsumerApplicationElement;
use App\ConsumerApplicationFiles;
use App\Http\Controllers\Admin\ConsumerApplicationController;
use App\Http\Controllers\Admin\ConsumerDocument;
use App\Http\Controllers\Admin\DisbursementController;
use App\JobProvider;
use App\LiabilityLog;
use App\MultiStageDisbursement;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Slack;
use Illuminate\Support\Facades\Storage;
use App\ApplicationEMICalculation;
use App\CreditReport;
use Illuminate\Support\Facades\Mail;

class AvanseDisbursementInstruction
{

    public $error = null;
    private $request;
    public $service = null;

    public function __construct(Request $request)
    {

        $this->request = $request;
    }

    public function getPayload()
    {

        if ($this->service) {
            $service = $this->service;
            return $this->$service();
        }

        if (!$this->dataInitialize()){
            return false;
        }

        return [
            "finReference" =>  $this->request->get('fin_reference_id'),
            "disbursements" =>  [
                [

                    "disbParty" => "TP",//CS, TP - Third Part
                    "disbType" => "NEFT",
                    "disbDate" => date('Y-m-d\TH:i:s', Carbon::createFromFormat('d/m/Y',$this->request->get('disbDate'))->timestamp),
                    "disbAmount" => round($this->request->get('disAmount')) * 100,//$this->request->get('net_disbursement_amount') * 100,
                    "partnerBankId" => "46",
                    "remarks" => "",
                    "issueBank" => $this->request->get('merchant_bank_details')->bank_name,//"ABHY",
                    "favourName" => "",
                    "payableLoc" => "",
                    "printingLoc" => "",
                    "chequeNo" => "",
                    "valueDate" => date('Y-m-d\TH:i:s'), //date('Y-m-d\TH:i:s', strtotime($this->request->get('disbDate')))
                    "bankCode" => "", //"ABHY",
                    "branchCode" => "", //"ABHY0065005",
                    "ifsc" => $this->request->get('merchant_bank_details')->ifsc_code,
                    "accountNo" => $this->request->get('merchant_bank_details')->account_number,
                    "acHolderName" => $this->request->get('merchant_bank_details')->account_holder,
                    "phoneCountryCode" => "",
                    "phoneAreaCode" => "",
                    "phoneNumber" => "",
                    "vasReference" => ""
                ]
            ]
        ];
    }

    private function getDisbursementInstructions(){
        $avanseFinance = AvanseCreateFinance::where('application_id', $this->request->get('id'))->first(['id', 'finReference']);

        if (!isset($avanseFinance->id)){
            $this->error[] = 'Please create loan for avanse before creating disbursement instruction';
            return false;
        }

        return [
            'finReference' => $avanseFinance->finReference
        ];
    }

    private function addDisbursementInstructionsTranches(){
        $avanseFinance = AvanseCreateFinance::where('application_id', $this->request->get('id'))->first(['id', 'finReference']);

        if (!isset($avanseFinance->id)){
            $this->error[] = 'Please create loan for avanse before creating disbursement instruction';
            return false;
        }

        if (!$this->dataInitialize()){
            return false;
        }

        $consumerApplicationController = new ConsumerApplicationController();
        $multistage = $consumerApplicationController->getPartialDisbursementData($this->request, new MultiStageDisbursement());

        $disbursementData = $this->getDisbursementData($multistage);

        return [
                "finReference" => $avanseFinance->finReference,
                "fromDate" => date('Y-m-d\TH:i:s', strtotime($this->request->get('disbDate'))),
                "amount" => $disbursementData['total_amount'] * 100,
                "reCalType" => "TILLMDT",
                "reCalFromDate" => date('Y-m-d\TH:i:s', strtotime($this->request->get('disbDate'))),
                "reCalToDate" => "",
                "terms" => 0,
                "reqType" => "Post",
                "disbursements" => $disbursementData['disbursement']
            ];
    }

    private function getDisbursementData($multistage){
        $disbursement = [];
        $total_amount = 0;
        foreach ($multistage as $item) {
            $disbursement = [
                "disbParty" => "TP",
                "disbType" => "NEFT",
                "disbDate" => date('Y-m-d\TH:i:s', strtotime($item->date)),
                "disbAmount" => $item->disbursement_amount * 100,
                "partnerBankId" => "46",
                "remarks" => "",
                "favourName" => "",
                "bankCode" => "", //"ABHY",
                "branchCode" => "", //"ABHY0065005",
                "ifsc" => $this->request->get('merchant_bank_details')->ifsc_code,
                "accountNo" => $this->request->get('merchant_bank_details')->account_number,
                "acHolderName" => $this->request->get('merchant_bank_details')->account_holder
            ];

            $total_amount += $item->disbursement_amount;
        }

        return ['disbursement' => $disbursement, 'total_amount' => $total_amount];
    }

    private function dataInitialize(){
        $application = ConsumerApplication::with('merchant_bank_details','activeOffer','avanse','avanseByApplicant','merchant','emi','proFormaInvoice', 'application_element.merchant_center.bank_details')->where('id', $this->request->get('id'))->first(['id','merchant_id','approved_amount','applicant_id','offer_id']);

        if(!$application->avanse && !$application->avanseByApplicant){
            $this->error[] = 'Please create customer for avanse before creating loan';
            return false;
        }

        if (!$application->merchant_bank_details){
            $this->error[] = 'Please add merchant bank details';
            return false;
        }

        //$disbursementController = new DisbursementController($this->request);
        //$net_disbursement_amount = $disbursementController->getDisbursementAmount($application)['net_disbursement'];

        $avanseFinance = AvanseCreateFinance::where('application_id', $application->id)->first(['id', 'finReference']);
        if (!isset($avanseFinance->id)){
            $this->error[] = 'Please create loan for avanse before creating disbursement instruction';
            return false;
        }

        $consumerApplicationElement = ConsumerApplicationElement::where('application_id', $this->request->get('id'))->first(['id', 'payment_transfer_date']);
        if (!isset($consumerApplicationElement->id) || (isset($consumerApplicationElement->id) && !$consumerApplicationElement->payment_transfer_date)){
            $this->error[] = 'Please enter disbursement Date';
            return false;
        }



        $subvention = $this->getSubventionAmountAvanse($application);

        $merchant_collected_advance_amount = $application->proFormaInvoice && $application->proFormaInvoice->merchant_collected_advance_amount ? $application->proFormaInvoice->merchant_collected_advance_amount : 0;

        $avanseProcesses = new AvanseProcesses($this->request);
        $disAmount = $avanseProcesses->getNetAmountAsPerAvanse($subvention['WithGST']);
        if($application->activeOffer->advance_type == 'emi' && $merchant_collected_advance_amount && $application->emi){
            $disAmount -= $application->emi->upfront_from_customer;
        }

        if(in_array($application->id, [201473,204827])){
            $disAmount -= 1;
        }
        if(in_array($application->id, [])){
            $disAmount -= 2;
        }

        //$this->mandateApproval();
        return $this->request->merge([
            'merchant_bank_details' => $this->getBankDetails($application),
            'net_disbursement_amount' => isset($net_disbursement_amount) ? $net_disbursement_amount : 0,
            'fin_reference_id' => $avanseFinance->finReference,
            'disbDate' => $consumerApplicationElement->payment_transfer_date,
            'subvention' => $subvention['WithGST'],
            'disAmount' => $disAmount
        ]);
    }

    public function getBankDetails($application){
        $bankDetail = 1;

        $is_gst_applicable = $application->merchant->is_gst ?? 0;
        $bank_details = $application->application_element->merchant_center->bank_details ?? '';

        $user['center_bank'] = $bank_details;
        $user['center_gst_number'] = $application->application_element->merchant_center->gst_number ?? '';

        if ($is_gst_applicable == 0 && isset($user['center_bank']->account_holder)){
            if ($user['center_bank']->account_holder && empty($user['center_gst_number'])){
                $bankDetail = 0;
            }else if(!empty($user['center_gst_number']) && !$user['center_bank']->account_holder){
                $bankDetail = 1;
            }else if(!empty($user['center_gst_number']) && $user['center_bank']->account_holder){
                $bankDetail = 0;
            }else if(empty($user['center_gst_number']) && !$user['center_bank']->account_holder){
                $bankDetail = 1;
            }
        }else{
            if (isset($user['center_bank']->account_holder) && $user['center_bank']->account_holder && empty($user['center_gst_number'])){
                $bankDetail = 1;
            }else if(!empty($user['center_gst_number']) && (!isset($user['center_bank']->account_holder) || !$user['center_bank']->account_holder)){
                $bankDetail = 1;
            }else if(!empty($user['center_gst_number']) && (isset($user['center_bank']->account_holder) && $user['center_bank']->account_holder)){
                $bankDetail = 0;
            }else if(empty($user['center_gst_number']) && (!isset($user['center_bank']->account_holder) || !$user['center_bank']->account_holder)){
                $bankDetail = 1;
            }
        }
        if ($bankDetail){
            return $application->merchant_bank_details;
        }else{
            return $user['center_bank'];
        }
    }

    public function getSubventionAmountAvanse($application){
        $charge_subvention_remaining_amount = $application->merchant && $application->merchant->charge_subvention_remaining_amount ? 1 : 0;
        $downPayment = 0;
        if($charge_subvention_remaining_amount){
            $downPayment = $application->emi->upfront_from_customer;
        }
        $subvention_amount = (($application->approved_amount - $downPayment)*$application->emi->subvention)/100;

        $multiStageDisbursement = (new MultiStageDisbursement())->getSubventionInvoiceAmount($application, $subvention_amount);
        $subvention_amount = isset($multiStageDisbursement['subvention_amount']) ? $multiStageDisbursement['subvention_amount'] : $multiStageDisbursement;

        if ($subvention_amount) {
            $gstDetailsSubvention = (new ConsumerDocument(new Request()))->getGSTDetails(
                [
                    'amount' => $subvention_amount,
                    'state' => $application->merchant->state
                ]
                ,0, $application->lender_id);
            
            $subventionWithGST = $gstDetailsSubvention[0]['net_amount'];
            $gst_on_subvention = 0;
            foreach ($gstDetailsSubvention as $item){
                $subventionWithGST += $item['gst_amount'];
                $gst_on_subvention += $item['gst_amount'];
            }

            return ['WithGST' => round($subventionWithGST), 'gst_on_subvention'=>round($gst_on_subvention), 'Net' => $gstDetailsSubvention[0]['net_amount']];
        }

        return ['WithGST' => 0, 'gst_on_subvention'=>0, 'Net' => 0];
    }

    public function saveResponse(AvanseDisbursementInstruction $avanseDisbursementInstruction, $response){
        if ($response){
            try {

                if (!isset($response->returnStatus->returnCode) || $response->returnStatus->returnCode != '0000'){
                    $avanseDisbursementInstruction->error = isset($response->returnStatus->returnText) ? $response->returnStatus->returnText : 'Avanse: Incomplete data found!';
                    return false;
                }

                if($avanseDisbursementInstruction->service == 'getDisbursementInstructions'){
                    $avanseDisbursementStatus = AvanseDisbursementStatus::insertGetId([
                        'application_id' => $this->request->get('id'),
                        'finReference' => $this->request->get('finReference') ?? $avanseDisbursementInstruction->getPayload()['finReference'],
                        'response' => json_encode($response),
                        'created_at' => Carbon::now()->toDateTimeString()
                    ]);
                    if (isset($avanseDisbursementStatus)) {
                        $this->request->merge(['avanse_disbursement_status_id' => $avanseDisbursementStatus]);
                        if (isset($response->disbResponse)){
                            $processed = [];
                            foreach ($response->disbResponse as $disRes){
                                if (strtolower($disRes->status) == 'paid'){

                                    if(isset($disRes->transactionRef) && !in_array($disRes->transactionRef, $processed)) {
                                        $application = new ConsumerApplicationController();
                                        $application->webhook($this->request->get('id'), ['status' => 'utr', 'type' => 'UTR-Webhook', 'data' => $application->getMConnectPayload($this->request->get('id'), 'utr', ['utr' => $disRes->transactionRef])]);
                                        $processed[] = $disRes->transactionRef;
                                    }

                                    (new ConsumerApplicationController())->updateApplicationStatus($this->request->get('id'), 'disbursed');
                                    break;
                                }else{
                                    $this->reInnateAdvanceStatusUpdate();
                                }
                            }
                        }
                        return $avanseDisbursementStatus;
                    }
                }elseif($avanseDisbursementInstruction->service == 'addDisbursementInstructionsTranches'){
                    $avanseDisbursementStatus = AvanseDisbursementStatus::insertGetId([
                        'application_id' => $this->request->get('id'),
                        'finReference' => $this->request->get('finReference'),
                        'response' => json_encode($response),
                        'created_at' => Carbon::now()->toDateTimeString()
                    ]);
                    if (isset($avanseDisbursementStatus)) {
                        $this->request->merge(['avanse_disbursement_status_id' => $avanseDisbursementStatus]);
                        return $avanseDisbursementStatus;
                    }
                }else {
                    $disbursementInstructions = [];

                    if (isset($response->disbursements)) {

                        $paymentId = isset($response->disbursements[0]) && $response->disbursements[0]->paymentId ? $response->disbursements[0]->paymentId : false;

                        $created_at = Carbon::now()->toDateTimeString();
                        foreach ($response->disbursements as $disbursement) {
                            $disbursementInstructions[] = [
                                'application_id' => $this->request->get('id'),
                                'paymentId' => $disbursement->paymentId,
                                'finReference' => $disbursement->finReference,
                                'disbParty' => $disbursement->disbParty,
                                'disbType' => $disbursement->disbType,
                                'disbDate' => $disbursement->disbDate,
                                'disbAmount' => $disbursement->disbAmount,
                                'partnerBankId' => $disbursement->partnerBankId,
                                'created_at' => $created_at
                            ];
                        }

                        if ($disbursementInstructions) {
                            AvanseDisbursement::insert($disbursementInstructions);
                        }

                        if ($paymentId) {
                            $this->request->merge(['avanse_payment_id' => $paymentId]);
                            return $paymentId;
                        }
                    }
                }
            }catch (\Exception $exception){
                (new Slack(new Request(['title' => 'Request Error', 'fields' => ['response' => $response, 'request' => json_encode($this->request->all())]])))->send();
                return false;
            }
        }

        return $response;
    }

    public static function postDisbursementInstructionActions($appObj) {
        $to = _env('AVANSE_DISBURSEMENT_CASE_EMAIL_TO');
        $cc = _env('AVANSE_DISBURSEMENT_CASE_EMAIL_CC');

        // send email to applicant and co-applicant
        if(!empty($to) || !empty($cc)) {
            $application = ConsumerApplication::with('advisor','emi','emi_payment','merchant','proFormaInvoice','ConsumerApplicationElement.product','activeOffer')->whereNull('deleted_at')->where('id', $appObj->id)->first();
            $request = new Request(['id' => $appObj->id]);
//            $net_disbursement = round((new AvanseProcesses($request))->getNetAmountAsPerAvanse());//(new DisbursementController($request))->getDisbursementAmount($application)['net_disbursement'];
            $emiObj = ApplicationEMICalculation::where('application_id', $appObj->id)->first();
            $crdObj = CreditReport::where('application_id', $appObj->id)->where('applicant_type', 1)->first();
            $avId = AvanseCreateFinance::getAvanseLoanId($appObj->id);
            $avCustId = AvanseCreateCustomer::getAvanseCustomerId($appObj->id);
            //$caeObj = ConsumerApplicationElement::where('application_id', $appObj->id)->first(['application_id','hold_amount']);
            $to = explode(',', $to);
            $cc = explode(',', $cc);
            array_push($cc, $application->advisor->email);
            $emi_count = 0;
            if (!empty($emiObj->advance_emi) && !empty($emiObj->emi)) {
                $emi_count = intval($emiObj->advance_emi / $emiObj->emi);
            }
            if(empty($application->application_element->product->name)){
                $application->application_element->product_name = (new ConsumerApplicationController())->getProductName($application->application_element->product_name);
            }

            $charge_subvention_remaining_amount = $application->merchant && $application->merchant->charge_subvention_remaining_amount ? 1 : 0;
            /*$downPayment = 0;
            if($charge_subvention_remaining_amount){
                $downPayment = $application->emi->upfront_from_customer;
            }*/

            $subvention = (new AvanseDisbursementInstruction($request))->getSubventionAmountAvanse($application);

//            $subvention_amount = 0;
//            if($application->emi->subvention) {
//                $subvention_amount = (($application->approved_amount - $downPayment) * $application->emi->subvention) / 100;
//            }
//
//            if($subvention_amount) {
//                $gstDetailsSubvention = (new ConsumerDocument(new Request()))->getGSTDetails(
//                    [
//                        'amount' => $subvention_amount,
//                        'state' => (isset($application->permanent_address_state) && !empty($application->permanent_address_state)) ? $application->permanent_address_state : (isset($application->current_address_state) && !empty($application->current_address_state) ? $application->current_address_state : '')
//                    ]
//                );
//            }

            $merchant_collected_advance_amount = $application->proFormaInvoice && $application->proFormaInvoice->merchant_collected_advance_amount ? $application->proFormaInvoice->merchant_collected_advance_amount : 0;

            $disAmount = (new AvanseProcesses($request))->getNetAmountAsPerAvanse($subvention['WithGST']);
            if($application->activeOffer->advance_type == 'emi' && $merchant_collected_advance_amount && $application->emi){
                $disAmount -= $application->emi->upfront_from_customer;
            }

            $processing_fee = $emiObj->processing_fee;
            $proc_fee_by_merchant = 0;
            if(isset($application->proFormaInvoice) && $application->proFormaInvoice->processing_fee_by_merchant == 1)
            {
                $proc_fee_by_merchant = true;
            }


            if($application->activeOffer->advance_type == 'emi' && !$application->proFormaInvoice->merchant_collected_advance_amount && $application->emi) {
                $tenure = $application->emi->tenure - $application->emi->advance_emi;
                $advance_emi = 0;
            }else{
                $tenure = $application->emi->tenure;
                $advance_emi = $application->emi->advance_emi;
            }

            $no_of_emi = $application->emi ? $application->emi->remaining_emi : null;

            if(isset($application->proFormaInvoice) && $application->proFormaInvoice->merchant_collected_advance_amount == 0)
            {
               $advance_payment = 0;
            }else{
                $advance_payment = $application->emi->upfront_from_customer;
            }

            $files = ConsumerApplicationFiles::where('consumer_application_id', $appObj->id)->whereNotNull('password')->get(['id','file_type','password','bank_name']);

            $documentsHasPasswords = [];

            foreach ($files as $fileKey => $file){
                if($file->password) {
                    $documentsHasPasswords[] = ['id' => ($fileKey + 1), 'name' => str_replace('_',' ',ucwords($file->file_type)), 'password' => $file->password, 'bankName' => str_replace('_',' ',ucwords($file->bank_name))];
                }
            }

            $merchant_collected_advance_amount = $application->proFormaInvoice && $application->proFormaInvoice->merchant_collected_advance_amount ? $application->proFormaInvoice->merchant_collected_advance_amount : 0;
            $isMerchantCollected = $application->activeOffer->advance_type == 'emi' && $merchant_collected_advance_amount && $application->emi ? $application->emi->upfront_from_customer : 0;
            $comments = '';
            if(!$isMerchantCollected && $application->emi->upfront_from_customer) {
                $comments = 'Advance amount collected by merchant';
            }

            $liabilityLog = LiabilityLog::where('application_id', $appObj->id)->first(['id', 'liability_percent']);
            $hold_amount = 0;
            $disbAmountMinusPF = 0;
            if(isset($liabilityLog) && $liabilityLog->liability_percent) {
                if($proc_fee_by_merchant && $processing_fee){
                    $disbAmountMinusPF = $disAmount - $processing_fee;
                }
                $hold_amount = ($disbAmountMinusPF * $liabilityLog->liability_percent) / 100;
                $comments .= "<br/>".($hold_amount)." to be hold in DSRA";
            }

            $data = [
                'id' => $appObj->id,
                'loan_id' => !empty($avId) ? $avId : '',
                'borr_name' => $appObj->name,
                'co_borr_name' => !empty($appObj->co_applicant_name) ? $appObj->co_applicant_name : '',
                'av_cust_id' => !empty($avCustId) ? $avCustId : '',
                'amount' => round((new AvanseProcesses(new Request(['id' => $appObj->id])))->getNetAmountAsPerAvanse()),//$appObj->approved_amount,
                'net_disbursement' => $disAmount,
                'roi' => !empty($emiObj->interest_rate) ? $emiObj->interest_rate : '',
                'tenure' => $tenure,//!empty($emiObj->tenure) ? $emiObj->tenure : 0,
                'adv_pay' => $advance_payment,//$emiObj->advance_emi,
                'no_of_emi' => $no_of_emi,
                'proc_fee' => $processing_fee,
                'inst_name' =>!empty($application->merchant->merchant_name) ? $application->merchant->merchant_name : '',
                'prod_name' => !empty($application->application_element->product->name) ? $application->application_element->product->name : (!empty($application->application_element->product_name) ? $application->application_element->product_name : ''),
                'subvention_amount' => isset($subvention['Net']) ? $subvention['Net'] : 0,
                'hasPasswords' => $documentsHasPasswords,
                'comments' => $comments,
                'hold_amount' => $hold_amount ?? 0,
                'liability_percent' => $liabilityLog->liability_percent ?? 0,
                'proc_fee_by_merchant'=> $proc_fee_by_merchant
            ];
            $id = !empty($avId) ? $avId : '';
            $lid = $appObj->id;

            $isWhitelisted = isset($liabilityLog->id) ? '(Whitelisted case)' : '';

            Mail::send('emails.reminders.basic_reminder', [
                'body' => view('emails.reminders.disburse_case_send_to_avanse', $data),
                //'lender_id' => $appObj->lender_id,
                'is_include_footer' => false
            ], function ($message) use ($to, $cc, $id, $lid, $isWhitelisted) {
                $message->subject('New disbursement case '.$id.' - Credit Fair - '. $lid.' '.$isWhitelisted);
                if(!empty($cc)) {
                    foreach ($cc as $email) {
                        $message->cc($email);
                    }
                }
                if(!empty($to)) {
                    foreach ($to as $email) {
                        $message->to($email);
                    }
                }
            });
            unset($application, $request, $emiObj, $crdObj, $appObj, $data);
        }
        return true;
    }

    public function reInnateAdvanceStatusUpdate(){
        $job = JobProvider::where('application_id', $this->request->get('id'))->where('from', 'initiateUTRStatusAvanse')->first(['available_at']);
        if($job->available_at){
            if(Carbon::parse($job->available_at)->hour == 21){
                $available_at = Carbon::parse('tomorrow 12am')->toDateTimeString();
            }else{
                $available_at = Carbon::parse('today 9pm')->toDateTimeString();
            }
        }
        JobProvider::where('application_id', $this->request->get('id'))->where('from', 'initiateUTRStatusAvanse')->update(['is_available' => 0, 'available_at' => $available_at]);
    }

}
