<?php

namespace App;

use App\Http\Controllers\Admin\ConsumerDocument;
use App\Http\Controllers\Admin\DisbursementController;
use App\CFPayoutDirectTransfer;
use Carbon\Carbon;
use App\DisbursementRequests;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\DB;

class MultiStageDisbursement extends DisbursementLogs {

    private $request;

    public function __construct(array $attributes = [], Request $request = null){
        $this->request = $request ? $request : new Request();
        parent::__construct($attributes);
    }

    public function initPartialDisbursement($application, $process = array(), $phasePending = false, $appCount = 0)
    {

        $disbursement_phase = $this->isPartialDisbursement($application);

        if (is_bool($disbursement_phase))
            return $disbursement_phase;

        $disbursement_phase = count($disbursement_phase) == 0 ? 1 : count($disbursement_phase)+1;

        if($phasePending){
            $pendingPhase = $disbursement_phase-1;
            $disbursement_phase_no = $disbursement_phase;
            if($pendingPhase > 0){
                $pendingPhaseInfo = CFPayoutDirectTransfer::where('application_id',$application->id)->where('phase',$pendingPhase)->orderBy('id','desc')->first(['message','retry']);
                if(isset($pendingPhaseInfo->message) && (!in_array($pendingPhaseInfo->message,['SUCCESS']) && ($pendingPhaseInfo->retry == 0))){
                    // if(in_array($pendingPhaseInfo->message,['Transfer request pending at the bank','PENDING'])){
                        $disbursement_phase = $pendingPhase;
                    // }
                    if($appCount == 1){
                        if(in_array($pendingPhaseInfo->message,['FAILED'])){
                            $disbursement_phase = $disbursement_phase_no;
                        }
                    }
                }
            }
        }

        return $this->getPartialDisbursementData($application, $process, $disbursement_phase);
    }

    public function getPartialDisbursementData($application, $process, $disbursement_phase){
        $partialDisbursement = $this->getPartialDisbursementAmount($application, $disbursement_phase);


        if(isset($process['consumer_emi'])) {
            $process['consumer_emi']->partial_upfront_from_credit_fair = $partialDisbursement['disbursement_amount'];
            $process['consumer_emi']->partial_subvention_amount = $partialDisbursement['subvention'];
            $process['consumer_emi']->subvention_igst = $partialDisbursement['igst'];
            $process['consumer_emi']->subvention_cgst = $partialDisbursement['cgst'];
            $process['consumer_emi']->subvention_sgst = $partialDisbursement['sgst'];

            $process['partial_disbursement'] = [
                'amount' => $partialDisbursement['disbursement_amount_before'],
                'phase' => $partialDisbursement['phase'],
                'percentage_amount' => $partialDisbursement['per_disbursement_amount']
            ];
        }
        $disburseData = Carbon::parse($process['disbursed_date'] ?? Carbon::now()->toDateString())->addDays($partialDisbursement['day_from_disbursement_date']);
        $disburseDate = Carbon::now()->timestamp < $disburseData->timestamp ? Carbon::now()->toDateString() : $disburseData->toDateString();
        $process = array_merge($process,['disbursement_phase' => $partialDisbursement['disbursement_phase_id'], 'phase_cycle' => $disbursement_phase, 'next_phase' => $partialDisbursement['phase'], 'disbursement_amount' => $partialDisbursement['disbursement_amount'], 'disbursed_date' => $disburseDate]);
        $forProcessingFeeInvoice = $process['invoice'];
        $invoice = Invoices::where('application_id', $application->id)->where('type', 'subvention_invoice')->where('phase_id', $partialDisbursement['phase'])->first();
        if ($invoice){
            $process['invoice'] = $invoice;
            $process['forProcessingFeeInvoice'] = $forProcessingFeeInvoice;
        }
        // return isset($process['consumer_emi']) ? $process : $partialDisbursement['disbursement_amount'];
        return $process;
    }


    public function getPartialDisbursementAmountV1($application, $disbursementOffersData, $phase){

        $disbursement_amount = ($application->approved_amount * $disbursementOffersData->per_disbursement_amount) / 100;

        if ($phase == 1) {
            $disbursement_amount -= $application->emi->upfront_from_customer;
        }
        return $disbursement_amount;
    }

    public function upFrontFromCreditFair($application, $withTrashed=false){

        $upFrontFromCreditFair = 0;
        if($withTrashed){
            $offer = MerchantOffers::with('merchant')->where('id', $application->emi->offer_id)->withTrashed()->first();
        }else{
            $offer = MerchantOffers::with('merchant')->where('id', $application->emi->offer_id)->first();
        }

        switch ($offer->interest_type_id){
            case 1:
                $subvention = ((($application->approved_amount - $application->emi->upfront_from_customer)*$application->emi->subvention)/100);
                $upFrontFromCreditFair = ($offer->interest_rate) ?  $application->approved_amount - $application->emi->upfront_from_customer - $subvention : $this->getupFrontFromCreditFair($application, $offer);
                break;
            case 2:
                $upFrontFromCreditFair = $application->approved_amount - $application->emi->upfront_from_customer - ($application->emi->subvention * ($application->approved_amount - $application->emi->upfront_from_customer))/100;
                break;
            case 3:
                $upFrontFromCreditFair = ($offer->interest_rate) ? $application->approved_amount - $application->emi->upfront_from_customer - (($application->approved_amount - $application->emi->upfront_from_customer) * $application->emi->subvention)/100 : ($application->approved_amount*($offer->tenure_remaining/$offer->tenure) - (($application->approved_amount - $application->emi->upfront_from_customer)*$application->emi->subvention)/100);
                break;
            case 4:
                $upFrontFromCreditFair = $application->approved_amount - $application->emi->upfront_from_customer - ((($application->approved_amount - $application->emi->upfront_from_customer) * $application->emi->subvention)/100);
                break;
        }

        return $upFrontFromCreditFair;
    }

    public function getupFrontFromCreditFair($application, $offer){
        $getupFrontFromCreditFair = ($application->approved_amount*($offer->tenure_remaining/$offer->tenure) - (($application->approved_amount - $application->emi->upfront_from_customer)*$application->emi->subvention)/100);;
        if ($offer->advance_type == 'percentage'){
            if ($application->emi->upfront_from_customer && $getupFrontFromCreditFair){
                return $getupFrontFromCreditFair - $application->emi->upfront_from_customer;
            }
        }
        return $getupFrontFromCreditFair;
    }


    public function getPartialDisbursementAmount($application, $disbursement_phase){

        $disbursementOffers = new DisbursementOffers();
        $disbursementOffersData = $disbursementOffers->getOfferDisbursement($application->emi->offer_id, $disbursement_phase, $application->id);
        $legal_charges = (new DisbursementController(new Request()))->getLegalChargesAmount($application);
        // (new Slack(new Request(['title' => 'Multistage error logs2', 'fields' => ['application_id' => $application->id]])))->send();

        if($application->merchant && $application->merchant->charge_subvention_remaining_amount && $disbursement_phase == 1){
            $subventionAmountOLD = (($application->approved_amount -  $application->emi->upfront_from_customer) * $application->emi->subvention) / 100;
            $subventionAmount = $subvention = ((($application->approved_amount * $disbursementOffersData->per_disbursement_amount) / 100) - $application->emi->upfront_from_customer) * $application->emi->subvention / 100;
            $newUpFrontFrontCreditFair = $application->emi->upfront_from_credit_fair;
            if(round($this->upFrontFromCreditFair($application)) == round($application->emi->upfront_from_credit_fair)) {
                $newUpFrontFrontCreditFair = (($application->emi->upfront_from_credit_fair + $subventionAmountOLD) - $subventionAmount);
                ApplicationEMICalculation::where('application_id', $application->id)->update(['upfront_from_credit_fair' => $newUpFrontFrontCreditFair]);
            }
            $upfront_from_credit_fair = $newUpFrontFrontCreditFair + $subventionAmount;
            // (new Slack(new Request(['title' => 'Multistage error logs3', 'fields' => ['application_id' => $application->id]])))->send();
        }else{
            $subventionAmount = ($application->approved_amount * $application->emi->subvention) / 100;
//            (new Slack(new Request(['title' => 'Multistage offers Issue log', 'fields' => ['id' => $application->id], 'group' => Slack::$STAGE_TESTING])))->send();
            // (new Slack(new Request(['title' => 'Multistage error logs4', 'fields' => ['application_id' => $application->id]])))->send();
            $subvention = $this->getMultiStageSubventionAmount($subventionAmount, $disbursementOffersData);
            $upfront_from_credit_fair = $application->emi->upfront_from_credit_fair + $subventionAmount;
        }

        $subventionGST = (new EMICalculation())->calculateGSTonSubvention($subvention, $application->approved_amount, $application->emi->offer_id, false, $application->id, true);

        $igst = $subventionGST['subvention_igst'];
        $cgst = $subventionGST['subvention_cgst'];
        $sgst = $subventionGST['subvention_sgst'];
        $gst_on_subvention = $igst + $cgst + $sgst;
        $subvention_with_gst = $subvention + $igst + $cgst + $sgst;

        $merchant_processing_collected =  (isset($application->proFormaInvoice) ? $application->proFormaInvoice->processing_fee_by_merchant : (isset($application->merchant->is_collected) ? $application->merchant->is_collected : 0));
        $merchant_advance_amount_collected =  (isset($application->proFormaInvoice) && $application->proFormaInvoice->merchant_collected_advance_amount == 1) ? 1 : 0;


        $disbursement_amount = $disbursement_amount_before = ($upfront_from_credit_fair * $disbursementOffersData->per_disbursement_amount) / 100;

        if ($application->emi->disbursement_method == 1){
            $disbursement_amount = $disbursement_amount_before = $this->getPartialDisbursementAmountV1($application, $disbursementOffersData, $disbursementOffersData->phase);
            if ($disbursementOffersData->phase == 1) {
                $disbursement_amount_before += $application->emi->upfront_from_customer; // with advance
            }
        }

        $insurance_premium_amount = isset($application->proFormaInvoice->insurance_premium_amount) && $application->proFormaInvoice->insurance_premium_applicable == 1 && $application->proFormaInvoice->insurance_premium_by_merchant == 1 ? $application->proFormaInvoice->insurance_premium_amount : 0;

        if($disbursementOffersData->phase > 1 && $insurance_premium_amount){
            $insurance_premium_amount = 0;
        }

        if ($merchant_processing_collected == 1) {
            $processing_fee = $disbursement_phase == 1 ? $application->emi->processing_fee : 0;
            $legal_fee = $disbursement_phase == 1 ? $legal_charges : 0;
            $disbursement_amount = $disbursement_amount - ($processing_fee + ($igst + $cgst + $sgst) + $subvention + $insurance_premium_amount) - $legal_fee;
        } else {
            $disbursement_amount = $disbursement_amount - ($igst + $cgst + $sgst + $subvention + $insurance_premium_amount);
        }

        if($merchant_advance_amount_collected && $disbursementOffersData->phase == 1){
            $disbursement_amount += $application->emi->upfront_from_customer;
        }
        // (new Slack(new Request(['title' => 'Multistage error logs5', 'fields' => ['application_id' => $application->id]])))->send();
        return ['disbursement_phase_id' => $disbursementOffersData->id, 'disbursement_amount_before' => $disbursement_amount_before, 'disbursement_amount' => $disbursement_amount, 'subvention' => $subvention, 'igst' => $igst, 'cgst' => $cgst, 'sgst' => $sgst, 'gst_on_subvention'=>$gst_on_subvention, 'subvention_with_gst'=> $subvention_with_gst, 'per_disbursement_amount' => $disbursementOffersData->per_disbursement_amount, 'day_from_disbursement_date' => $disbursementOffersData->day_from_disbursement_date, 'phase' => $disbursementOffersData->phase];
    }

    public function getMultiStageSubventionAmount($subventionAmount, $disbursementOffersData){
        return ($subventionAmount * $disbursementOffersData->per_disbursement_amount) / 100;
    }

    public function getPendingDisbursementProperties($id, $previousDisbursementOffers){
        $application = ConsumerApplication::with('merchant','emi.offer','proFormaInvoice')->where('id',$id)->first();
        $disbursementOffers = DisbursementOffers::whereNotIn('id', $previousDisbursementOffers)->where('application_id',$id)->where('offer_id', $application->emi->offer_id)->get();
        $pendingDisbursement = [];
//        (new Slack(new Request(['title' => 'Multistage offers Issue', 'fields' => ['id' => $id], 'group' => Slack::$STAGE_TESTING])))->send();
        if ($disbursementOffers){
            foreach ($disbursementOffers as $index => $offer){
                $pendingDisbursement[] = $this->getPartialDisbursementAmount($application, ($offer->phase));
            }
        }
        return $pendingDisbursement;
    }

    public function getTotalDisburseAmount($documentDetails){
        $igst = $documentDetails['user']['consumer_emi']->subvention_igst;
        $cgst = $documentDetails['user']['consumer_emi']->subvention_cgst;
        $sgst = $documentDetails['user']['consumer_emi']->subvention_sgst;
        if($documentDetails['user']['merchant_processing_collected'] == 1) {
            return ($documentDetails['user']['consumer_emi']->upfront_from_credit_fair - ($documentDetails['user']['consumer_emi']->processing_fee + ($igst + $cgst + $sgst)));
        }else{
            return ($documentDetails['user']['consumer_emi']->upfront_from_credit_fair - ($igst + $cgst + $sgst));
        }
    }

    public function getDisbursementProperties($id, $applicationData, $isSchedule = false){
        $disbursementOffers = new DisbursementOffers();
        $disbursementOffersData = $disbursementOffers->getOfferByID($applicationData['user']['disbursement_phase'], $id);

        if ($isSchedule)
            $this->scheduleNextPhaseSlack($disbursementOffers, $applicationData['user']['consumer_emi'], $disbursementOffersData->phase, $id);

        return [
            'application_id' => $id,
            'phase' => $disbursementOffersData->phase,
            'disbursement_amount' => $applicationData['user']['consumer_emi']['partial_upfront_from_credit_fair'],
            'partial_subvention_amount' => $applicationData['user']['consumer_emi']['partial_subvention_amount'],
            'per_disbursement_amount' => $disbursementOffersData->per_disbursement_amount,
            'day_from_disbursement_date' => $disbursementOffersData->day_from_disbursement_date,
            'disbursement_offer_id' => $disbursementOffersData->id,
            'created_by' => Auth::user() ? Auth::user()->id : (Input::has('auth_user_id') ? Input::get('auth_user_id') : 107),
            'created_at' => Carbon::now()->toDateTimeString()
        ];
    }

    public function saveDisbursementDataInLogs($disbursementOffersData){

        $disbursementLogs = DisbursementLogs::where('application_id', $disbursementOffersData['application_id'])->where('phase', $disbursementOffersData['phase'])->where('disbursement_offer_id', $disbursementOffersData['disbursement_offer_id'])->where('disbursement_amount', $disbursementOffersData['disbursement_amount'])->first(['id']);

        if(!isset($disbursementLogs->id)) {
            DisbursementLogs::insert($disbursementOffersData);
        }
        try {
            $existingRecords = DisbursementRequests::where('application_id', $disbursementOffersData['application_id'])->where('phase', $disbursementOffersData['phase']);

            if ($existingRecords->count() > 0) {
                // Update records in next_phase_disbursement_requests table
                $disbursementRequests = $existingRecords->get();
                foreach ($disbursementRequests as $disbursementRequest) {
                    $disbursementRequest->is_disbursed = true;
                    $disbursementRequest->save();
                }

            } else {
                // Handle if no corresponding record found in DisbursementLogs table
            }
        }catch (\Exception $e){
            (new Slack(new Request(['title'=>'Disbursement Request Error','fields'=>['error'=>$e->getMessage(),'line'=>$e->getLine(),'trace'=>$e->getTraceAsString(),'application_id'=>$disbursementOffersData['application_id']]])))->send();
        }
    }

    public function disbursedPartially($id, $applicationData){
        $disbursementOffersData = $this->getDisbursementProperties($id, $applicationData, true);
        // (new Slack(new Request(['title' => 'Multistage error logs6', 'fields' => ['application_id' => $id]])))->send();
        $this->saveDisbursementDataInLogs($disbursementOffersData);

        (new DisbursementController(new Request([
            'merchant_id' => isset($applicationData['user']['merchant_id']) ? $applicationData['user']['merchant_id'] : 0,
            'application_id' => $disbursementOffersData['application_id'],
            'total_amount_to_disbursed' => $disbursementOffersData['disbursement_amount'],
            'is_cancellation_adjusted' => 0,
            'is_multi_stage' => 1,
            'created_by' => Auth::user() ? Auth::user()->id : (Input::has('auth_user_id') ? Input::get('auth_user_id') : 107),
        ])))->startDisbursements();
        // (new Slack(new Request(['title' => 'Multistage error logs6', 'fields' => ['application_id' => $id]])))->send();
    }

    public function getSubventionInvoiceAmount($application, $subvention_amount = 0, $withTrashed = false){
        if ($this->canPartialDisbursement($application->emi->offer_id, $application)) {
            $disbursement_phase = $this->isPartialDisbursement($application);
            if (is_bool($disbursement_phase))
                return $subvention_amount;

            $disbursement_phase = count($disbursement_phase) == 0 ? 1 : count($disbursement_phase);

            $offerId = $application->emi->offer->id ?? $application->offer->id;

            $disbursementOffers = new DisbursementOffers();
            $disbursementOffersData = $disbursementOffers->getCurrentOfferDisbursement($offerId, $disbursement_phase, $application->id);
            if($application->merchant && $application->merchant->charge_subvention_remaining_amount && $disbursement_phase == 1) {
                $multiStageSubventionAmount = ((($application->approved_amount * $disbursementOffersData->per_disbursement_amount) / 100) - $application->emi->upfront_from_customer) * $application->emi->subvention / 100;
                $subventionAmountOLD = (($application->approved_amount -  $application->emi->upfront_from_customer) * $application->emi->subvention) / 100;
                if(round($this->upFrontFromCreditFair($application, $withTrashed)) == round($application->emi->upfront_from_credit_fair)) {
                    $newUpFrontFrontCreditFair = (($application->emi->upfront_from_credit_fair + $subventionAmountOLD) - $multiStageSubventionAmount);
                    ApplicationEMICalculation::where('application_id', $application->id)->update(['upfront_from_credit_fair' => $newUpFrontFrontCreditFair]);
                }
            }else{
                $multiStageSubventionAmount = $this->getMultiStageSubventionAmount($subvention_amount, $disbursementOffersData);
            }
            return ['subvention_amount' => $multiStageSubventionAmount, 'phase_id' => $disbursementOffersData->phase];
        }
        return $subvention_amount;
    }

    public function scheduleNextPhaseSlack(DisbursementOffers $disbursementOffers, $consumer_emi, $phase, $application_id){
        $disbursementOffersData = $disbursementOffers->getOfferDisbursement($consumer_emi->offer_id, $phase, $application_id);
        $disbursedDate = (new ConsumerDocument($this->request))->getDisbursedDate($application_id);

        if($disbursementOffersData) {
            $payload[] = [
                'payload' => json_encode($disbursementOffersData),
                'from' => 'partial_disbursement',
                'application_id' => $application_id,
                'available_at' => Carbon::parse($disbursedDate)->addDays($disbursementOffersData->day_from_disbursement_date)->toDateTimeString(),
                'created_at' => Carbon::now()->toDateTimeString()
            ];

            JobProvider::insert($payload);
        }
    }

    public function generateDisbursementOffers($id){
        $application = DB::connection('mysql_primary')
            ->table('emi_calculation')
            ->where('application_id', $id)
            ->first(['offer_id']);
        $disbursementOffersData = DisbursementOffersData::where('offer_id', $application->offer_id)->get()->toArray();
        DisbursementOffers::where('application_id', $id)->delete();
        if ($disbursementOffersData) {
            foreach ($disbursementOffersData as $disbursementOffer) {
                unset($disbursementOffer['id']);
                $disbursementOfferNew = (array)$disbursementOffer;
                $disbursementOfferNew['application_id'] = $id;
                $disbursementOfferNew['created_by'] = Auth::user() ? Auth::user()->id : (Input::has('auth_user_id') ? Input::get('auth_user_id') : 107);
                $disbursementOfferNew['created_at'] = Carbon::now()->toDateTimeString();
                DisbursementOffers::insert($disbursementOfferNew);
            }
        }
    }

    public function sendPartialDisbursementNotification($job, $payload){
        $application_id = $job->application_id;
        $application = ConsumerApplication::with('merchant')->where('id', $application_id)->first();
        $user = User::find($payload->created_by);
        $data = (array)$payload;
        $data['created_by'] = $user->name;
        $data['% Disbursement Amount'] = $data['per_disbursement_amount'];
        $data['merchant'] = $application->merchant ? $application->merchant->merchant_name : '';
        unset($data['updated_at']);
        unset($data['created_at']);
        unset($data['day_from_disbursement_date']);
        unset($data['offer_id']);
        unset($data['status']);
        unset($data['id']);
        unset($data['per_disbursement_amount']);
        $advisor_id[] = _env('APP_CONNECTION') ? 28 : 11;
        $advisor_id[] = isset($application->user_id) && isset($application->user_id) ? $application->user_id : '';
        $segment = User::where('id', $advisor_id)->first(['id', 'name', 'slack_id','slack_url']);
        if(isset($segment->slack_id) && $segment->slack_id) {
            (new Slack(new Request(['title' => 'Next Partial Disbursement of '.$application->name, 'fields' => $data, 'group' => 'loan_application','tagging' => $advisor_id])))->send();
            (new Slack(new Request(['title' => 'Next Partial Disbursement of '.$application->name, 'fields' => $data, 'group' => $segment->slack_url])))->send();
        }
    }

}
