<?php

namespace App\Http\Controllers\Admin;

use App\ApplicationEMICalculation;
use App\Avanse\Processes\AvanseProcesses;
use App\AvanseCreateDocument;
use App\AvanseDisbursement;
use App\Bank;
use App\BlackSoil;
use App\CancellationDisbursement;
use App\CFPayoutDirectTransfer;
use App\ConsumerApplication;
use App\ConsumerApplicationElement;
use App\ConsumerApplicationFiles;
use App\Disbursement;
use App\DisbursementSchedule;
use App\DisbursementSummary;
use App\EmiPayment;
use App\Http\Controllers\ApiController;
use App\Http\Controllers\Controller;
use App\JobProvider;
use App\Jobs;
use App\Lenders;
use App\LiabilityLog;
use App\Merchant;
use App\MerchantCategoryLegalCharges;
use App\MerchantOffers;
use App\MultiStageDisbursement;
use App\PaymentTransaction;
use App\Payout\PayoutAPI;
use App\PayoutCF\PayoutCFAPI;
use App\PayoutStatus;
use App\PendingBalance;
use App\ProFormaInvoice;
use App\RefundPayments;
use App\StatusLogs;
use App\WalletConfiguration;
use App\WalletLogs;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Singularity\Singularity;
use Illuminate\Support\Facades\DB;
use App\Logging\CloudWatchLoggerFactory;


class DisbursementController extends Controller
{
    private $request;
    private static $cancellation_fixed_charges = 0;

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

    public function disbursement($id = 0)
    {

        ini_set('max_execution_time', -1);
        set_time_limit(0);
        ini_set('memory_limit', '-1');

        $_app_id = $this->request->get('application_id');
        $_merchant_id = $this->request->get('merchant_id');
        $_lender_id = $this->request->get('_lender_id');
        $_by_amount = $this->request->get('by_amount');

        $applicationsFailed = false;
        $lenders = Lenders::get();
        $merchants = Merchant::get();

        $applications = ConsumerApplication::with('documents','payoutStatus', 'CFPayoutDirectTransfer', 'cancellation', 'merchant', 'emi', 'emi.offer', 'invoice', 'proFormaInvoice', 'pendingAdjustableAmount', 'application_element', 'offer')->where('state', 'ready for disbursement')->whereNull('is_deleted');

        if ($_app_id) {
            $applications = $applications->where('id', 'like', $_app_id . '%');
        }

        if ($_merchant_id) {
            $applications = $applications->where('merchant_id', $_merchant_id);
        }

        if ($_lender_id) {
            $applications = $applications->where('lender_id', $_lender_id);
        }

        if ($id) {
            $applications = ConsumerApplication::with('payoutStatus', 'CFPayoutDirectTransfer', 'cancellation', 'merchant', 'emi', 'emi.offer', 'invoice', 'proFormaInvoice', 'pendingAdjustableAmount', 'application_element', 'offer')->whereIn('state',['disbursed','nach registered'])->whereNull('is_deleted')->where('id', $id)->get(['id', 'merchant_id', 'name', 'approved_amount', 'offer_id']);
        } else {
            $applications = $applications->get(['id', 'merchant_id', 'name', 'approved_amount', 'offer_id', 'lender_id', 'purpose','updated_by']);
        }

        if (_env('payout') == 'paytm') {
            $payoutStatus = PayoutStatus::where('status', 'FAILURE')->where('retry', 0);
            if ($id) {
                $payoutStatus = $payoutStatus->where('application_id', $id);
            }
            $payoutStatus = $payoutStatus->get();


            $applicationIds = [];
            foreach ($payoutStatus as $payout) {
                $applicationIds[] = $payout->application_id;
            }
        } else {
            $payoutStatus = new CFPayoutDirectTransfer();
            if ($id) {
                $payoutStatus = $payoutStatus->where('application_id', $id);
            }
            $payoutStatus = $payoutStatus->orderBy('id', 'desc')->whereNull('deleted_at')->get(['application_id', 'message', 'retry']);

            $applicationIds = [];
            $applicationIdsTemp = [];
            foreach ($payoutStatus as $payout) {

                if ((isset($payout->message) && $payout->message == 'SUCCESS') || $payout->retry == 1) {
                    $applicationIdsTemp[] = $payout->application_id;
                }

                if (!in_array($payout->application_id, $applicationIdsTemp)) {
                    $applicationIds[] = $payout->application_id;
                }
            }
        }

        if ($applicationIds) {
            $applicationsFailed = ConsumerApplication::with('payoutStatus', 'CFPayoutDirectTransfer', 'cancellation', 'merchant', 'emi', 'emi.offer', 'invoice', 'proFormaInvoice', 'pendingAdjustableAmount', 'application_element', 'offer')->whereIn('state', ['disbursed', 'nach registered'])->whereNull('is_deleted');
            if ($_app_id) {
                $applicationsFailed = $applicationsFailed->where('id', 'like', $_app_id . '%');
            } if ($_merchant_id) {
                $applicationsFailed = $applicationsFailed->where('merchant_id', $_merchant_id);
            }
            if ($_lender_id) {
                $applicationsFailed = $applicationsFailed->where('lender_id', $_lender_id);
            }
            $applicationsFailed = $applicationsFailed->whereIn('id', $applicationIds)->get(['id', 'merchant_id', 'name', 'approved_amount', 'offer_id']);
            if ($applications) {
                $applications = $applications->merge($applicationsFailed);
            } else {
                $applications = $applicationsFailed;
            }
        }

        $response = [];
        $offerIssues = [];
        $receivedIds = [];
        $customersProcessed = [];
        $processedPayments = [];

        $idsProcessing = [];

        foreach ($applications as $application) {

            if ($application->emi && isset($application->emi->offer->id)) {

                $disbursementAmount = $this->getDisbursementAmount($application);
                $exception_list = [];
                $multiStageExists = false;
                $multiStageDisbursement = new MultiStageDisbursement();
                if ($multiStageDisbursement->canPartialDisbursement($application->emi->offer->id, $application)) {
                    if (isset($id) && $id != 0) {
                        $appCount = 1;
                    } else {
                        $appCount = count($applications);
                    }
                    if ($multiStageDisbursementData = $multiStageDisbursement->initPartialDisbursement($application, ['invoice' => $application->invoice], true, $appCount)) {
                        $multiStageExists = true;
                        if (isset($application->application_element->multi_tranche_exception_list)) {
                            $exception = json_decode($application->application_element->multi_tranche_exception_list, true);
                            foreach ($exception as $k => $doc) {
                                if ($doc['name'] == 'CAM') {
                                    $doc['link'] = \request()->getSchemeAndHttpHost() . '/admin/consumer-applications/edit/' . $application->id . '?docs=1&href=nav-documents-tab&#nav-documents-tab';
                                }
                                if ($doc['name'] == 'repayment history') {
                                    $doc['link'] = \request()->getSchemeAndHttpHost() . '/admin/payment/start_v1/' . $application->id;
                                }
                                if ($doc['name'] == 'latest bureau') {
                                    $doc['link'] = \request()->getSchemeAndHttpHost() . '/admin/consumer-applications/edit/' . $application->id . '?docs=1&href=nav-documents-tab&#nav-documents-tab';
                                }
                                if ($doc['name'] == 'latest bank statement') {
                                    $doc['link'] = \request()->getSchemeAndHttpHost() . '/admin/consumer-applications/edit/' . $application->id . '?docs=1&href=nav-documents-tab&#nav-documents-tab';
                                }
                                if ($doc['name'] == 'CPV') {
                                    $doc['link'] = \request()->getSchemeAndHttpHost() . '/admin/consumer-applications/edit/' . $application->id . '?docs=1&href=nav-documents-tab&#nav-documents-tab';
                                }
                                if (!in_array($doc['name'], ['CAM', 'repayment history', 'latest bureau', 'latest bank statement', 'CPV'])) {
                                    $doc['link'] = \request()->getSchemeAndHttpHost() . '/admin/consumer-applications/edit/' . $application->id . '?docs=1&href=nav-documents-tab&#nav-documents-tab';
                                }
                                array_push($exception_list, $doc);
                            }
                        }
                        if ($multiStageDisbursementData['phase_cycle'] > 2) {
                            $multiStageExists = false;
                        }
                        if (!is_bool($multiStageDisbursementData)) {
                            $disbursementAmount['net_disbursement'] = $multiStageDisbursementData['disbursement_amount'];
                        }
                    }
                }


                $received = 0;
                $customers = [];
                $processedPayments = [];
                $merchant = Merchant::with('adjustable_transaction.application')->where('id', $application->merchant_id)->first(['id', 'merchant_name']);
                if (isset($merchant->adjustable_transaction)) {
                    foreach ($merchant->adjustable_transaction as $adjustable_transaction) {
                        if ($adjustable_transaction->amount && !in_array($adjustable_transaction->id, $receivedIds)) {
                            $received += $adjustable_transaction->amount;

                            $processedPaymentItem = ['application_id' => $adjustable_transaction->application_id, 'amount' => (float)$adjustable_transaction->amount, 'type' => 'emi', 'transaction_id' => $adjustable_transaction->id, 'merchant_id' => $adjustable_transaction->application->merchant_id, 'name' => $adjustable_transaction->application->name, 'is_processed' => 1];

                            /*if($received > $disbursementAmount['net_disbursement']){
                                $received -= $adjustable_transaction->amount;
                                $processedPaymentItem['is_processed'] = 0;
                                $processedPayments[] = $processedPaymentItem;
                                continue;
                            }*/

                            $processedPayments[] = $processedPaymentItem;

                            $receivedIds[] = $adjustable_transaction->id;
                            $applicationData = ConsumerApplication::where('id', $adjustable_transaction->application_id)->first(['id', 'name']);
                            if (isset($applicationData->name) && $applicationData->name && !in_array($applicationData->id, $customersProcessed)) {
                                $customers[] = $applicationData->name;
                                $customersProcessed[] = $applicationData->id;
                            }
                        }
                    }
                }

                // $application->emi->upfront_from_credit_fair;
                $response[$application->merchant_id]['applications'][$application->id] = $application;
                $response[$application->merchant_id]['multiStage'][$application->id] = $multiStageExists;
                $response[$application->merchant_id]['exceptionList'][$application->id] = $exception_list;
                // added the liability percent logic to net disbursement amount
                $withhold = 0;
                if ($application->application_element && $application->application_element->hold_amount) {
                    $withhold = $application->application_element->hold_amount;
                } else {
                    $liabilityLog = LiabilityLog::where('application_id', $application->id)->orderBy('created_at', 'desc')->first(['liability_amount']);
                    if (isset($liabilityLog->liability_amount) && $liabilityLog->liability_amount) {
                        $withhold = $liabilityLog->liability_amount;
                    }
                }
                $response[$application->merchant_id]['details'][$application->id] = ['withhold' => $withhold, 'net_disbursement_before' => $disbursementAmount['net_disbursement'], 'received' => $received, 'name' => implode(', ', $customers), 'receivedIds' => $receivedIds, 'currentPhase' => $multiStageDisbursementData['phase_cycle'] ?? 0];
                $response[$application->merchant_id]['cancellation'] = $application->cancellation;
                $response[$application->merchant_id]['pendingAdjustableAmount'] = $application->pendingAdjustableAmount;
                $response[$application->merchant_id]['previous_adjustable_amount'] = $this->getPreviousAdjustableAmount($application);

                $status_log = DB::SelectOne("SELECT id, created_at FROM status_logs WHERE application_id = ? AND status = 'disbursement checklist done' ORDER BY created_at DESC LIMIT 1", [$application->id]);
                if($application->merchant_id == _env("SSE_MERCHANT_ID") && isset($status_log->id) && $status_log->created_at >= '2025-11-05 00:00:00') { // date condition added for issues in 2nd phase of disbursement
                    // Handle SSE_MERCHANT_ID specific logic here
                    $documentType = 'advance_amount_receipt';
                    $sscDisburseMessage = null;
                    $sscDisburse = $this->getDocumentsStatus($application, $documentType, $callFromDisbPage = true);
                    if ($sscDisburse == '3') {
                        $sscDisburseMessage = 'Advance amount receipt review is pending';
                    }else if($sscDisburse == '0'){
                        $sscDisburseMessage = 'Advance amount / Down Payment receipt is pending or rejected';
                    }else if($sscDisburse == '1'){
                        $sscDisburseMessage = 'Advance amount / Down Payment receipt document verification is pending';
                    }
                    $response[$application->merchant_id]['applications'][$application->id]['ssc_disbursement_status'] = $sscDisburseMessage;
                }
                foreach ($processedPayments as $processedPayment) {
                    $response[$application->merchant_id]['processed_transaction'][] = $processedPayment;
                }

                if (!isset($response[$application->merchant_id]['received'])) {
                    $response[$application->merchant_id]['received'] = $received;
                } else {
                    $response[$application->merchant_id]['received'] += $received;
                }

                $idsProcessing[] = $application->id;
            }else{
                $offerIssues[] = [
                    'id' => $application->id,
                    'name' => $application->name,
                    'lender_id' => $application->lender_id
                ];
            }
        }

        $jobsProcessing = JobProvider::whereIn('application_id', $idsProcessing)->where('from', 'InvokeCommunicationPayout')->where('is_available', 0)->get(['application_id']);
        $jobsProcessingIds = [];
        if ($jobsProcessing) {
            foreach ($jobsProcessing as $item) {
                $jobsProcessingIds[] = $item->application_id;
            }
        }


        foreach ($response as $merchant_id => $item) {
            if (isset($item['processed_transaction'])) {
                if (!isset($response[$merchant_id]['processed_payments'])) {
                    $response[$merchant_id]['processed_payments'] = $item['processed_transaction'];
                } else {
                    $response[$merchant_id]['processed_payments'] = array_merge($response[$merchant_id]['processed_payments'], $item['processed_transaction']);
                }
            }

            foreach ($item['cancellation'] as $cancellationItem) {
                $response[$merchant_id]['processed_payments'][] = ['id' => $cancellationItem->id, 'application_id' => $cancellationItem->application_id, 'name' => $cancellationItem->application->name, 'amount' => (float)$cancellationItem->total_amount_adjusted, 'type' => 'cancellation', 'merchant_id' => $cancellationItem->merchant_id];
            }

            foreach ($item['pendingAdjustableAmount'] as $pendingAdjustableAmountItem) {
                $response[$merchant_id]['processed_payments'][] = ['application_id' => $pendingAdjustableAmountItem->application_id, 'amount' => $pendingAdjustableAmountItem->pending, 'type' => $pendingAdjustableAmountItem->type, 'merchant_id' => $pendingAdjustableAmountItem->merchant_id, 'pending_balance_id' => $pendingAdjustableAmountItem->id];
            }
        }

        $showOptions = (new ConsumerApplicationController())->getPermissions();
        $canDisbursed = 0;
        if (in_array('disbursed', $showOptions)) {
            $canDisbursed = 1;
        }

        if (_env('payout') == 'paytm') {
            $wallets = (new PayoutAPI($this->request))->getDisbursalAccountLists();
        }
        $walletConfiguration = WalletConfiguration::first();
        $merchants = Merchant::where('pre_status', 0)->where('status', 'active')->get(['id', 'merchant_name']);
        $lenders = Lenders::get(['id', 'name']);

        return view('admin.disbursement', ['data' => $response, 'canDisbursed' => $canDisbursed, 'wallets' => $wallets ?? [], 'walletConfiguration' => $walletConfiguration, 'jobsProcessingIds' => $jobsProcessingIds, 'lenders' => $lenders, 'merchants' => $merchants, '_lender_id' => $_lender_id, 'merchant_id' => $_merchant_id, 'application_id' => $_app_id, 'offerIssues' => $offerIssues]);
    }

    public function getPreviousAdjustableAmount($application)
    {
        $pendingAmount = PendingBalance::where('merchant_id', $application->merchant_id)->where('pending', '>', 0)->sum('pending');
        //$merchant = Merchant::where('id', $application->merchant_id)->where('status','active')->where('is_guest_active',1)->first(['pending_adjustable_amount']);
        return $pendingAmount;
    }

    
    public function getDocumentsStatus($application, $fileType = null, $callFromDisbPage = false)
    {
        if($fileType == 'advance_amount_receipt') {
            if ($this->isAdvancePaymentVerified($application) || !$callFromDisbPage) {
                return $this->getDocVerificationStatus($application, $fileType);
            }else{
                return '3';
            }
        } else {
            return $this->getDocVerificationStatus($application, $fileType);
        }

        return '0'; // This indicates that the file is not uploaded or rejected
    }

    private function isAdvancePaymentVerified($application)
    {
        return !empty($application->application_element) &&
            $application->application_element->advance_payment_verified;
    }

    private function getDocVerificationStatus($application, $fileType)
    {
        $latestDoc = $this->getLatestDocumentByType($application, $fileType);

        if (is_null($latestDoc)) {
            return '0'; // This indicates that the document does not exist
        }

        if (is_null($latestDoc->doc_verify)) {
            return '1'; // This indicates that the document is not verified
        } elseif ($latestDoc->doc_verify === 0) {
            return '0'; // This indicates that the document is verified and rejected
        }

        return '2'; // This indicates that the document is verified
    }


    private function getLatestDocumentByType($application, $fileType)
    {
        if (empty($application->documents)) {
            return null;
        }

        return $application->documents
            ->where('file_type', $fileType)
            ->sortByDesc('id')
            ->first();
    }

    public function startDisbursements()
    {
        $consumer = ConsumerApplication::with('emi', 'emi_payment', 'merchant', 'proFormaInvoice', 'application_element','disbursementOfferDisbursed')->where('id', $this->request->get('application_id'))->first();

        if(!$this->request->has('is_multi_stage')){
            if(count($consumer->disbursementOfferDisbursed) > 0){
                $request = new Request();
                $request->request->add([
                    'type' => 'Pro Forma Invoice',
                    'bot' => true
                ]);
                $document = (new ConsumerDocument($request));
                $applicationData = $document->getDocument($this->request->get('application_id'));
                if(isset($applicationData['user']['disbursement_phase']) && $applicationData['user']['disbursement_phase']) {
                    $multiStageDisbursement = new MultiStageDisbursement();
                    $disbursementOffersData = $multiStageDisbursement->getDisbursementProperties($this->request->get('application_id'), $applicationData, false);

                    $this->request->request->add([
                    '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,
                    'created_by' => Auth::user() ? Auth::user()->id : 107]);
                }

                if($consumer->state == 'nach registered'){
                    $payload = [
                        'payload' => json_encode(array_merge(['id' => $consumer->id, 'status' => $consumer->state, 'previous_status' => 'disbursed', 'auth_user_id' => 107, 'lender_id' => $consumer->lender_id])),
                        'from' => 'statusChange',
                        'application_id' => $consumer->id,
                        'available_at' => Carbon::now()->toDateTimeString(),
                        'created_at' => Carbon::now()->toDateTimeString()
                    ];
                    JobProvider::insert($payload);
                }
                if($consumer->state == 'disbursed'){
                    $payload = [
                        'payload' => json_encode(array_merge(['id' => $consumer->id, 'status' => $consumer->state, 'previous_status' => 'ready for disbursement', 'auth_user_id' => 107, 'lender_id' => $consumer->lender_id])),
                        'from' => 'statusChange',
                        'application_id' => $consumer->id,
                        'available_at' => Carbon::now()->toDateTimeString(),
                        'created_at' => Carbon::now()->toDateTimeString()
                    ];
                    JobProvider::insert($payload);
                }
            }
        }

        $disbursement_data = $this->request->has('disbursement_data') ? $this->request->get('disbursement_data') : '';
        $merchant_id = $this->request->get('merchant_id');
        $total_amount_adjusted = $this->request->has('total_amount_adjusted') ? $this->request->get('total_amount_adjusted') : 0;
        $total_amount_to_disbursed = $this->request->has('total_amount_to_disbursed') ? $this->request->get('total_amount_to_disbursed') : 0;
        $amount_to_be_adjusted = $this->request->has('amount_to_be_adjusted') ? $this->request->get('amount_to_be_adjusted') : 0;
        $application_id = $this->request->get('application_id');
        $amount_to_be_adjust_in_next_dis = $this->request->has('amount_to_be_adjust_in_next_dis') ? $this->request->get('amount_to_be_adjust_in_next_dis') : 0;
        $m_emi_amount_adjusted = $this->request->has('m_emi_amount_adjusted') ? $this->request->get('m_emi_amount_adjusted') : 0;
        $processed_payments = $this->request->has('processed_payments') ? $this->request->get('processed_payments') : 0;
        $m_up_front_cf = $this->request->has('m_up_front_cf') ? $this->request->get('m_up_front_cf') : 0;
        $is_cancellation_adjusted = $this->request->get('is_cancellation_adjusted');
        $search_filter = $this->request->has('search_filter') ? $this->request->get('search_filter') : '';
        //$amount_to_be_adjust_in_next_dis += $total_amount_adjusted > $amount_to_be_adjusted ? ($total_amount_adjusted - $amount_to_be_adjusted) : 0;

        if (_env('payout') == 'paytm') {
            $payStatus = PayoutStatus::where('application_id', $application_id)->where('status', 'FAILURE')->first(['id']);
        } else {
            $payStatus = CFPayoutDirectTransfer::where('application_id', $application_id)->orderBy('created_at', 'desc')->get(['id', 'message']);
            foreach ($payStatus as $payStatusItem) {
                if (in_array($payStatusItem->message, ['SUCCESS', 'PENDING']) || $payStatusItem->retry) {
                    $payStatus = null;
                    break;
                }
            }

        }
        if (isset($payStatus->id)) {
            $application = (new ConsumerApplicationController());
            $application->InvokeCommunicationPayout($application_id, 1);
            return response(['status' => 'OK']);
        }

        $dataObject = null;
        if (!$this->request->has('is_multi_stage')) {
            if(!isset($applicationData['user']['phase_cycle'])){
                $application = (new ConsumerApplicationController());
                $dataObj = $application->updateApplicationStatus($application_id, 'disbursed');
                if($dataObj->getData()->status == 'OK'){
                    $dataObject = ['status'=>'OK'];
                }
            }else if(isset($applicationData['user']['phase_cycle']) && $applicationData['user']['phase_cycle'] == 1){
                $application = (new ConsumerApplicationController());
                $dataObj = $application->updateApplicationStatus($application_id, 'disbursed');
                if($dataObj->getData()->status == 'OK'){
                    $dataObject = ['status'=>'OK'];
                }
            }else if(isset($applicationData['user']['phase_cycle']) && $applicationData['user']['phase_cycle'] > 1){
                StatusLogs::insert([
                    'application_id' => $application_id,
                    'user_id' => Auth::user() ? Auth::user()->id : 107,
                    'status' => 'Disbursement Phase'.$applicationData['user']['phase_cycle'],
                    'reason' => '',
                    'is_reversed' => 0,
                    'created_at' => Carbon::now()->toDateTimeString()
                ]);
                $dataObject = ['status'=>'OK'];
            }
        }

        // $consumer = ConsumerApplication::with('emi', 'emi_payment', 'merchant', 'proFormaInvoice', 'application_element')->where('id', $application_id)->first();

        $withhold = 0;
        if ($consumer->application_element && !$consumer->application_element->withhold_adjusted) {
            $withhold = ($consumer->application_element && $consumer->application_element->hold_amount ? $consumer->application_element->hold_amount : 0);
        }

        $net_disbursementAmount = $this->getDisbursementAmount($consumer);
        $net_disbursement = $net_disbursementAmount['net_disbursement'];

        /*if (!$total_amount_to_disbursed){
            $total_amount_to_disbursed = $consumer->emi && $consumer->emi->upfront_from_credit_fair ? $net_disbursement : 0;
        }*/

        /*if($this->request->get('ids')) {
            $cancellationIds = [];
            foreach ($this->request->get('ids') as $id) {
                $cancellationIds[] = $id['id'];
            }
        }*/

        if ($this->request->get('emiAdjusted')) {
            $emiAdjusted = [];
            $cancellationIds = [];
            foreach ($this->request->get('emiAdjusted') as $id) {
                if (isset($id['id'][0]) && isset($id['id'][0]['emi'])) {
                    array_push($emiAdjusted, $id['id'][0]['emi']);
                } else if (isset($id['id'][0]) && isset($id['id'][0]['cancellation'])) {
                    array_push($cancellationIds, $id['id'][0]['cancellation']);
                }
            }
        }

        if (isset($emiAdjusted) && !empty($emiAdjusted)) {
            PaymentTransaction::whereIn('id', $emiAdjusted)->update([
                'adjusted_to' => $application_id,
                'adjusted_by' => Auth::user()->id
            ]);
        }

        if (isset($cancellationIds) && $cancellationIds) {
            CancellationDisbursement::whereIn('id', $cancellationIds)->update([
                'adjusted_to' => $application_id
            ]);
        }

        $disb_data = [
            'application_id' => $application_id,
            'merchant_id' => $merchant_id,
            'disbursed' => $total_amount_to_disbursed < 0 ? 0 : $total_amount_to_disbursed,
            'emi_amount_adjusted' => $m_emi_amount_adjusted,
            'upfront_from_credit_fair' => $consumer->emi && $consumer->emi->upfront_from_credit_fair ? $net_disbursement : 0,
            'adjusted_amount' => $amount_to_be_adjusted,
            'total_amount_adjusted' => $total_amount_adjusted < 0 ? 0 : $total_amount_adjusted,
            'is_cancellation_adjusted' => $is_cancellation_adjusted,
            'adjusted_against' => isset($cancellationIds) ? json_encode($cancellationIds) : '',
            'emi_adjusted' => isset($emiAdjusted) ? json_encode($emiAdjusted) : '',
            'pending_adjustable_amount' => $amount_to_be_adjust_in_next_dis,
            'disbursement_data' => json_encode($disbursement_data),
            'withhold' => $withhold,
            'created_by' => $this->request->get('created_by'),
            'created_at' => Carbon::now()->toDateTimeString()
        ];

        (new ApplicationEMIDetailsController())->main($application_id, $disb_data);

        if (!$this->request->has('is_multi_stage')) {
            Disbursement::insert($disb_data);
        }


        /*$request = new Request();
        $request->request->add([
            'type' => 'Pro Forma Invoice',
            'bot' => true
        ]);
        $document = (new ConsumerDocument($request));
        $documentDetails = $document->getDocument($application_id);

        if(isset($documentDetails['user']['disbursement_phase']) && $documentDetails['user']['disbursement_phase']) {

            $multiStageDisbursement = new MultiStageDisbursement();
            $disbursementOffersData = $multiStageDisbursement->getDisbursementProperties($application_id, $documentDetails, true);
            $multiStageDisbursement->saveDisbursementDataInLogs($disbursementOffersData);
        }*/


        if ($withhold) {
            ConsumerApplicationElement::where('application_id', $application_id)->update(['withhold_adjusted' => $application_id]);
        }

        if ($processed_payments) {

            usort($processed_payments, function ($item1, $item2) {
                return $item2['amount'] <=> $item1['amount'];
            });

            $remaining_amount = $amount_to_be_adjusted;
            foreach ($processed_payments as $processed_payment) {
                if ($processed_payment['is_processed']) {
                    if ($remaining_amount >= $processed_payment['amount']) {
                        $remaining_amount -= $processed_payment['amount'];
                        $reconciliation[] = ['application_id' => $processed_payment['application_id'], 'pending' => 0, 'amount' => $processed_payment['amount'], 'status' => 'success', 'adjusted_to' => $application_id, 'type' => $processed_payment['type'], 'transaction_id' => (isset($processed_payment['transaction_id']) ? $processed_payment['transaction_id'] : 0), 'created_at' => Carbon::now()->toDateTimeString(), 'merchant_id' => $processed_payment['merchant_id'], 'pending_balance_id' => (isset($processed_payment['pending_balance_id']) ? $processed_payment['pending_balance_id'] : 0)];
                    } else if ($remaining_amount > 0 && $processed_payment['amount'] > 0 && $remaining_amount <= $processed_payment['amount']) {
                        $_remaining_amount = $processed_payment['amount'] - $remaining_amount;
                        $reconciliation[] = ['application_id' => $processed_payment['application_id'], 'pending' => $_remaining_amount, 'amount' => $remaining_amount, 'status' => 'success', 'adjusted_to' => $application_id, 'type' => $processed_payment['type'], 'transaction_id' => (isset($processed_payment['transaction_id']) ? $processed_payment['transaction_id'] : 0), 'created_at' => Carbon::now()->toDateTimeString(), 'merchant_id' => $processed_payment['merchant_id'], 'pending_balance_id' => (isset($processed_payment['pending_balance_id']) ? $processed_payment['pending_balance_id'] : 0)];
                        $remaining_amount = 0;
                    } else {
                        $reconciliation[] = ['application_id' => $processed_payment['application_id'], 'pending' => $processed_payment['amount'], 'amount' => 0, 'status' => 'pending', 'adjusted_to' => 0, 'type' => $processed_payment['type'], 'transaction_id' => (isset($processed_payment['transaction_id']) ? $processed_payment['transaction_id'] : 0), 'created_at' => Carbon::now()->toDateTimeString(), 'merchant_id' => $processed_payment['merchant_id'], 'pending_balance_id' => (isset($processed_payment['pending_balance_id']) ? $processed_payment['pending_balance_id'] : 0)];
                    }
                }
            }
        }

        if (isset($reconciliation)) {
            foreach ($reconciliation as $item) {
                if ($item['pending_balance_id']) {
                    $pendingBalance = PendingBalance::where('id', $item['pending_balance_id'])->first(['pending']);
                    if (isset($pendingBalance->pending) && $pendingBalance->pending > $item['amount']) {
                        $pendingAmount = $pendingBalance->pending;
                        $adjustedAmount = 0;
                        if ($item['amount'] == 0) {
                            $adjustedAmount = ($item['amount'] ? $item['amount'] : $item['pending']);
                            $pendingAmount = ($pendingBalance->pending - $adjustedAmount);
                        }
                        PendingBalance::where('id', $item['pending_balance_id'])->update(['pending' => $pendingAmount, 'amount' => $adjustedAmount, 'adjusted_to' => $item['adjusted_to']]);
                    } else if (isset($pendingBalance->pending) && $pendingBalance->pending == $item['amount']) {
                        PendingBalance::where('id', $item['pending_balance_id'])->update(['pending' => 0, 'adjusted_to' => $item['adjusted_to']]);
                    }

                }
            }
        }

        if (isset($reconciliation)) {
            foreach ($reconciliation as $key => $item) {
                unset($item['pending_balance_id']);
                PendingBalance::insert($item);
            }
        }

        Merchant::where('id', $merchant_id)->update(['pending_adjustable_amount' => $amount_to_be_adjust_in_next_dis]);

        $dataObject['url'] = $search_filter;
        return $dataObject;
    }

    public function getDisbursementAmount($application)
    {
        $net_disbursement = $net_disbursement_before = $application->emi->upfront_from_credit_fair - ($application->emi->subvention_igst + $application->emi->subvention_cgst + $application->emi->subvention_sgst);

        $processing_fee_by_merchant = $this->isProcessingFeeApplicable($application);
        $insurance_fee_by_merchant = $this->isInsuranceFeeApplicable($application);
        $advance_amount = $this->isCFCollectingAdvance($application);
//        $legal_charges = $this->getLegalChargesAmount($application);
        $legal_charges = $application->emi->legal_charges ?? $this->getLegalChargesAmount($application);

        if ($advance_amount) {
            $net_disbursement += $advance_amount;
        }

        if ($processing_fee_by_merchant) {
            $net_disbursement -= $application->emi->processing_fee;
            $net_disbursement -= $legal_charges;
        }
        if ($insurance_fee_by_merchant) {
            $net_disbursement -= $insurance_fee_by_merchant;
        }
        return [
            'net_disbursement' => $net_disbursement,
            'net_disbursement_before' => $net_disbursement_before,
        ];
    }

    /**
     * Returns Rs. 118 CERSAI Hypothecation charge for KMGC lender (lender_id = 2) when
     * the application's loan amount exceeds the merchant's hypothecation_charges threshold.
     * The threshold is set per merchant: 50,000 for Non-SSE, 10,00,000 for SSE.
     */
    public function getCersaiHypothecationCharge($application,$is_loan_amount_changed=False): int
    {
        $cwFactory = new CloudWatchLoggerFactory();
        $application_id = $application->id ?? null;

        $proFormaInvoice = $application->proFormaInvoice ?? ProFormaInvoice::where('application_id', $application->id)->first();

        if (!$is_loan_amount_changed) {
            if ($proFormaInvoice && !is_null($proFormaInvoice->cersai_hypothecation_charge)) {
                return (int) $proFormaInvoice->cersai_hypothecation_charge;
            }
        }

        $kmgcLenderId = 2;
        $blacksoilLenderId = BlackSoil::$lender_id;
        $charge = 0;
        $shouldUpdateProForma = false; 

        if ($application->lender_id == $kmgcLenderId || $application->lender_id == $blacksoilLenderId) {

            // temporary application overwritten since loan amount not present for disbursements page
            $_application = ConsumerApplication::where('id', $application->id)->first();

            $wasApprovedBeforeToday = StatusLogs::where('application_id', $_application->id)
                ->where('status', 'approved')
                ->where('created_at', '<', '2026-03-17 17:30:00')
                ->exists();

            if (!$wasApprovedBeforeToday) {

                $merchant = (isset($_application->merchant) && $_application->merchant)
                    ? $_application->merchant
                    : Merchant::find($_application->merchant_id);

                if ($merchant && !is_null($merchant->hypothecation_charges)) {
                    $cwFactory->logger(json_encode([
                        'application_id' => $application_id,
                        'message' => 'Merchant exists and has hypothecation_charges set',
                        'line' => __LINE__,
                        'values' => [
                            'merchant_id' => $merchant->id ?? $_application->merchant_id, 
                            'merchant_hypothecation_charges' => $merchant->hypothecation_charges
                        ]
                    ]));

                    $net_loan_amount = 0;
                    $offerId = $_application->offer_id ?? null;
                    
                    if (!empty($offerId)) {
                        $cwFactory->logger(json_encode([
                            'application_id' => $application_id,
                            'message' => 'Offer ID is present',
                            'line' => __LINE__,
                            'values' => ['offerId' => $offerId]
                        ]));

                        $active_offer = MerchantOffers::where('id', $offerId)->first();
                        
                        if ($active_offer) {
                            $loan_amount = $_application->loan_amount ?? 0;
                            $autoBRE = new autoBRE();
                            $net_loan_amount = $autoBRE->calculateNetLoanAmount($loan_amount, $active_offer);

                            $cwFactory->logger(json_encode([
                                'application_id' => $application_id,
                                'message' => 'Active offer found, calculated net_loan_amount',
                                'line' => __LINE__,
                                'values' => [
                                    'loan_amount' => $loan_amount, 
                                    'net_loan_amount' => $net_loan_amount
                                ]
                            ]));

                            if (!empty($merchant->hypothecation_charges) && $merchant->hypothecation_charges != 0) {
                                $charge = (int) env('CERSAI_HYPOTHECATION_CHARGE_ABOVE_5L', 118);

                                // Sub-Rs.5L CERSAI (Rs.59) applies only to applications approved on/after the
                                // release date. Older applications (approved before) retain the earlier flat
                                // charge (Rs.118).        
                                $cersaiBelow5lReleaseDate = '2026-06-12 00:00:00';
                                $latestApprovedLog = StatusLogs::where('application_id', $_application->id)
                                    ->where('status', 'approved')
                                    ->orderBy('created_at', 'desc')
                                    ->first(['created_at']);
                                $approvedBeforeBelow5lRelease = $latestApprovedLog
                                    && Carbon::parse($latestApprovedLog->created_at)->lt(Carbon::parse($cersaiBelow5lReleaseDate));
                                if ($net_loan_amount < 500000 && !$approvedBeforeBelow5lRelease) {
                                    $charge = (int) env('CERSAI_HYPOTHECATION_CHARGE_BELOW_5L', 59);
                                }
                                $cwFactory->logger(json_encode([
                                    'application_id' => $application_id,
                                    'message' => 'net_loan_amount is >= merchant hypothecation_charges, setting charge',
                                    'line' => __LINE__,
                                    'values' => [
                                        'net_loan_amount' => $net_loan_amount, 
                                        'merchant_hypothecation_charges' => $merchant->hypothecation_charges, 
                                        'charge' => $charge
                                    ]
                                ]));
                            }
                            if ($net_loan_amount >= 50000) {
                                $shouldUpdateProForma = true;
                            }
                        }
                    }
                }
            }
        }

        if ($proFormaInvoice && $shouldUpdateProForma) {
            $cwFactory->logger(json_encode([
                'application_id' => $application_id,
                'message' => 'Saving updated cersai_hypothecation_charge to ProFormaInvoice',
                'line' => __LINE__,
                'values' => ['charge_saved' => $charge]
            ]));

            $proFormaInvoice->cersai_hypothecation_charge = $charge;
            $proFormaInvoice->save();
        }

        return $charge;
    }

    public function getLegalChargesAmount($application){
        $blacksoilLenderId = BlackSoil::$lender_id;
        if ($application->lender_id == $blacksoilLenderId) {
            return env('BLACKSOIL_LEGAL_CHARGES_AMOUNT', 300);
        }

        $apiController = new ApiController();
        $isHypothecationActive = $apiController->canHypothecated($application->id);
        if ($isHypothecationActive) {
            if(!$application->purpose || !$application->merchant_id){
                $app = ConsumerApplication::where('id', $application->id)->first(['purpose','merchant_id']);
            }
            $purpose = $application->purpose ?? $app->purpose;
            $merchant_id = $application->merchant_id ?? $app->merchant_id;

            $categoryRules = MerchantCategoryLegalCharges::where('category_id', $purpose)->orderBy('created_at','desc')->first();
            if($categoryRules) {
                $caObj = new ConsumerApplicationController();
                if ($application->lender_id == Singularity::$lender_id) {
                    $legalChargesCheckAmount = $application->approved_amount - $application->emi->upfront_from_customer ?? 0;
                } else {
                    $legalChargesCheckAmount = $application->approved_amount;
                }
                $conditionMet = $caObj->evaluateLegalChargesCondition($legalChargesCheckAmount, $categoryRules->condition, $categoryRules->net_loan_amount, $merchant_id, $application->id);
                if ($conditionMet) {
                    $exceptional_ids = explode(',',_env('STAMP_SERIES_SPECIFIC_CASES'));
                    if($legalChargesCheckAmount > 500000 || in_array($application->id, $exceptional_ids)) {
                        $legalChargesAmount = 300;
                    }else{
                        $legalChargesAmount =  $categoryRules->legal_charges;
                    }
                    return $legalChargesAmount;
                }
            }
        }
        return 0;
    }

    public function isInsuranceFeeApplicable($application)
    {
        $proFormaInvoice = isset($application->proFormaInvoice) ? $application->proFormaInvoice : ProFormaInvoice::where('application_id', $application->id)->first();
        if ((isset($proFormaInvoice->insurance_premium_applicable) && $proFormaInvoice->insurance_premium_applicable == 1 && $proFormaInvoice->insurance_premium_by_merchant == 1 && $proFormaInvoice->insurance_premium_amount > 0)) {
            return $proFormaInvoice->insurance_premium_amount;
        }
        return false;
    }

    public function isCustomerPayingInsuranceFee($application)
    {
        $proFormaInvoice = isset($application->proFormaInvoice) ? $application->proFormaInvoice : ProFormaInvoice::where('application_id', $application->id)->first();
        if ((isset($proFormaInvoice->insurance_premium_applicable) && $proFormaInvoice->insurance_premium_applicable == 1 && $proFormaInvoice->insurance_premium_by_merchant == 0 && $proFormaInvoice->insurance_premium_amount > 0)) {
            return $proFormaInvoice->insurance_premium_amount;
        }
        return false;
    }

    public function isCFCollectingAdvance($application)
    {
        if (isset($application->proFormaInvoice) && $application->proFormaInvoice->merchant_collected_advance_amount && $application->emi) {
            return $application->emi->upfront_from_customer;
        }
        return false;
    }

    public function isProcessingFeeApplicable($application)
    {
        /*$merchantCollected = Merchant::where('id',$application->merchant_id)->where('is_collected', 1)->first(['id']);
        if(!isset($merchantCollected->id)){
            return false;
        }*/
        /*if(isset($merchantCollected->id)){
            if((isset($application->proFormaInvoice->processing_fee_by_merchant) && $application->proFormaInvoice->processing_fee_by_merchant == 1)){
                return true;*/
        /*$accountingController = new AccountingController();
        $processingDue = $accountingController->getApplicationDueAmount($application->id);
        if ($processingDue['processing_fee_due'] == 0) {
            return false;
        }*/
        /*}
    }*/

        $proFormaInvoice = $application->proFormaInvoice ?? ProFormaInvoice::where('application_id', $application->id)->first();

        if ((isset($proFormaInvoice->processing_fee_by_merchant) && $proFormaInvoice->processing_fee_by_merchant == 1)) {
            return true;
            /*$accountingController = new AccountingController();
            $processingDue = $accountingController->getApplicationDueAmount($application->id);
            if ($processingDue['processing_fee_due'] == 0) {
                return false;
            }*/
        }
        if (!isset($proFormaInvoice->id)) {
            $merchantCollected = Merchant::where('id', $application->merchant_id)->where('is_collected', 1)->first(['id']);
            if (isset($merchantCollected->id)) {
                return true;
            }
        }

        return false;
    }

    public function getDisbursementData()
    {
        $cancellation = ConsumerApplication::with('emi', 'emi_payment', 'merchant', 'proFormaInvoice', 'lender.banks')->whereNull('deleted_at')->where('id', $this->request->get('application_id'))->first(['id', 'merchant_id', 'name', 'approved_amount', 'lender_id']);

        $net_disbursementAmount = $this->getDisbursementAmount($cancellation);

        $disbursement_cancellation = $net_disbursementAmount['net_disbursement'];

        if (isset($cancellation->emi_payment) && count($cancellation->emi_payment) > 0) {
            $received = 0;
            foreach ($cancellation->emi_payment as $item) {
                $received = $item->total_payable - $item->amount_due;
                if ($received > $item->emi_amount) {
                    $received -= $item->emi_amount;
                }
            }

            $cancellation->received = $received;

            $disbursement_cancellation -= $received;
        }

        //$processing_fee_by_merchant = $cancellation->proFormaInvoice && $cancellation->proFormaInvoice->processing_fee_by_merchant == 1 ? $cancellation->proFormaInvoice->processing_fee_by_merchant : (isset($cancellation->merchant->is_collected) && $cancellation->merchant->is_collected == 1 ? $cancellation->merchant->is_collected : 0);

        /*if (!$processing_fee_by_merchant) {
            $processing_fee_by_merchant = $this->isProcessingFeeReceived($cancellation);
        }*/
        $processing_fee_by_merchant = $this->isProcessingFeeReceived($cancellation);

        $cancellation->processing_fee_by_merchant = $processing_fee_by_merchant;
        $cancellation->disbursement_cancellation = $disbursement_cancellation;
        $cancellation->cancellation_fixed_charges = static::$cancellation_fixed_charges;
        $cancellation->net_disbursement_before = $net_disbursementAmount['net_disbursement_before'];
        $cancellation->disbursement_summary = $this->getDisbursementSummary($cancellation);
        return response()->json(['status' => 'OK', 'data' => $cancellation]);
    }

    public function getDisbursementSummary($cancellation)
    {

        $data = $cancellation->emi;

        $subvention = 0;

        if ($data->subvention) {
            $subvention = ($cancellation->approved_amount * $data->subvention) / 100;
        }

        $processing_fee_by_merchant = $cancellation->proFormaInvoice && $cancellation->proFormaInvoice->processing_fee_by_merchant == 1 ? $cancellation->proFormaInvoice->processing_fee_by_merchant : (isset($cancellation->merchant->is_collected) && $cancellation->merchant->is_collected == 1 ? $cancellation->merchant->is_collected : 0);

        $processing_fee = 0;

        if ($processing_fee_by_merchant) {
            $processing_fee = $data->processing_fee;
        }


        return [
            ['name' => 'Sanction Amount', 'sign' => '+', 'value' => $cancellation->approved_amount],
            ['name' => 'Advance Amount', 'sign' => '-', 'value' => $data->upfront_from_customer],
            ['name' => 'Processing Fee', 'sign' => '-', 'value' => $processing_fee],
            ['name' => 'Subvention Charged', 'sign' => '-', 'value' => $subvention],
            ['name' => 'IGST', 'sign' => '-', 'value' => $data->subvention_igst],
            ['name' => 'CGST', 'sign' => '-', 'value' => $data->subvention_cgst],
            ['name' => 'SGST', 'sign' => '-', 'value' => $data->subvention_sgst]
        ];
    }

    public function isProcessingFeeReceived($application)
    {
        $accountingController = new AccountingController();
        $processingDue = $accountingController->getApplicationDueAmount($application->id);
        if ($processingDue['processing_fee_due'] > 0) {
            return 1;
        } else {
            return 0;
        }
    }

    public function initCancellationDisbursement()
    {

        $cancellationInterestCharges = $this->request->has('cancellation_interest_charges') && !empty($this->request->get('cancellation_interest_charges')) ? $this->request->get('cancellation_interest_charges') : 0;
        $cancellation_fixed_charges = $this->request->has('cancellation_fixed_charges') && !empty($this->request->get('cancellation_fixed_charges')) ? $this->request->get('cancellation_fixed_charges') : 0;

        $cancellationDisbursement = CancellationDisbursement::insert(
            [
                'application_id' => $this->request->get('application_id'),
                'merchant_id' => $this->request->get('merchant_id'),
                'cancellation_interest_charges' => $cancellationInterestCharges,
                'cancellation_fixed_charges' => $cancellation_fixed_charges,
                'total_amount_adjusted' => $this->request->get('total_amount_adjusted'),
                'total_amount_before_adjusted' => $this->request->get('total_amount_before_adjusted'),
                'adjusted_by' => $this->request->get('adjusted_by'),
                'created_at' => Carbon::now()->toDateTimeString()
            ]
        );

        $status = 'FAIL';
        if ($cancellationDisbursement) {
            $status = 'OK';

            $final_amount = ($this->request->get('total_amount_before_adjusted') + $cancellationInterestCharges + $cancellation_fixed_charges);
            if ($this->request->get('total_amount_adjusted') < $final_amount) {
                $merchant = Merchant::where('id', $this->request->get('merchant_id'))->first(['pending_adjustable_amount']);
                $amount = $_amount = ($final_amount - $this->request->get('total_amount_adjusted'));
                if ($merchant->pending_adjustable_amount) {
                    $amount += $merchant->pending_adjustable_amount;
                }

                PendingBalance::insert(['application_id' => $this->request->get('application_id'), 'pending' => $_amount, 'amount' => 0, 'status' => 'pending', 'adjusted_to' => 0, 'type' => 'cancellation_adjustment', 'transaction_id' => 0, 'created_at' => Carbon::now()->toDateTimeString(), 'merchant_id' => $this->request->get('merchant_id')]);
                Merchant::where('id', $this->request->get('merchant_id'))->update(['pending_adjustable_amount' => $amount]);
            }

        }
        return response(['status' => $status]);
    }

    public function getDisbursementAdjustment($disbursements)
    {

        foreach ($disbursements as $index => $disbursement) {
            $paymentTransaction = PaymentTransaction::where('adjusted_to', $disbursement->application_id)->get(['application_id']);
            $cancellationDisbursement = CancellationDisbursement::where('adjusted_to', $disbursement->application_id)->get(['application_id']);

            $applicationsIds = [];
            foreach ($paymentTransaction as $payment) {
                $applicationsIds[] = $payment->application_id;
            }
            foreach ($cancellationDisbursement as $cancellation) {
                $applicationsIds[] = $cancellation->application_id;
            }

            $customerName = [];
            if ($applicationsIds) {
                $consumerApplications = ConsumerApplication::whereIn('id', array_unique($applicationsIds))->get(['id', 'name']);
                foreach ($consumerApplications as $_customerName) {
                    $customerName[$_customerName->id] = $_customerName->name;
                }
                $disbursements[$index]->customer_name = $customerName;
            }
        }
        return $disbursements;
    }

    public function updateWalletConfiguration()
    {

        try {
            if ($this->request->has('wallet_config_id') && $this->request->get('wallet_config_id')) {
                $walletConfiguration = WalletConfiguration::find($this->request->get('wallet_config_id'));
            } else {
                $walletConfiguration = new WalletConfiguration();
            }

            $walletConfiguration->subWalletGuid = $this->request->get('subWalletGuid');
            $walletConfiguration->user_id = $this->request->get('user_id');
            $walletConfiguration->created_at = Carbon::now()->toDateTimeString();
            $walletConfiguration->save();


            WalletLogs::insert([
                'subWalletGuid' => $this->request->get('subWalletGuid'),
                'user_id' => $this->request->get('user_id'),
                'created_at' => Carbon::now()->toDateTimeString()
            ]);
        } catch (\Exception $e) {
            return response()->json(['status' => 'FAIL', 'message' => 'Can\'t update the wallet'], 200);
        }

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

    }

    public function removeFromFailedList()
    {

        if (_env('payout') == 'paytm') {
            PayoutStatus::where('application_id', $this->request->get('id'))->update(['retry' => 1]);
        } else {
            CFPayoutDirectTransfer::where('application_id', $this->request->get('id'))->update(['retry' => 1]);
        }
        return response()->json(['status' => 'OK'], 200);
    }

    public function dump()
    {
        $emiPayments = EmiPayment::where('emi_date', '<=', Carbon::now()->toDateString())->groupBy('application_id')->get(['application_id']);

        $applications = [];
        foreach ($emiPayments as $emiPayment) {
            if (!in_array($emiPayment->application_id, $applications)) {
                $applications[] = $emiPayment->application_id;
            }
        }

        $summary = DisbursementSummary::whereIn('application', $applications)->get(['application_id']);

        $applications = [];
        foreach ($summary as $item) {
            if (!in_array($item->application_id, $applications)) {
                $applications[] = $item->application_id;
            }
        }

        foreach ($emiPayments as $emiPayment) {
            $accountingController = new AccountingController();
            $schedule = $accountingController->viewloanschedule($emiPayment->application_id, 1);


            if (in_array($emiPayment->application_id, $applications)) {
                //update
            } else {
                //insert

                $disbursementSummary = new DisbursementSummary();
                $disbursementSummary->fill($schedule['summary']);
                $disbursementSummary->save();

                foreach ($schedule['schedule'] as $scheduleItem) {
                    $disbursementSchedule = new DisbursementSchedule();
                    $disbursementSchedule->disbursement_summary_id = $disbursementSummary->id;
                    $disbursementSchedule->fill($scheduleItem);
                    $disbursementSchedule->save();
                }
            }
        }
    }

    public function createDisbursementInstruction()
    {
        $avanseDisbursement = AvanseDisbursement::where('application_id', $this->request->get('id'))->first(['id']);
        if (isset($avanseDisbursement->id)) {
            return response()->json(['status' => 'OK', 'avanse_disbursement_id' => $avanseDisbursement->id]);
        }
        $avanseProcesses = new AvanseProcesses($this->request);

        $application = ConsumerApplication::where('id', $this->request->get('id'))->first(['id', 'offer_id']);
        $multiStageDisbursement = new MultiStageDisbursement();

        $documents = AvanseCreateDocument::with('documents')->where('application_id', $this->request->get('id'))->get();
        $mandatoryFileLists = ['aadhar_card' => ['aadhar_card'], 'pan_card' => ['pan_card'], 'customer_photo' => ['customer_photo']];
        $nonMandatoryFileLists = ['finbit' => ['finbit', 'fin bit'], 'bank statement' => ['bank statement'], 'itr' => ['itr'], 'salary_slip' => ['salary_slip']];
        foreach ($documents as $_document) {
            if (isset($_document->documents)) {
                foreach ($_document->documents as $document) {
                    $mandatoryFileLists = array_map(function ($item) use ($mandatoryFileLists, $document) {
                        if (!in_array(strtolower($document->file_type), $item)) {
                            return $item;
                        } else {
                            return [];
                        }
                    }, $mandatoryFileLists);
                    $nonMandatoryFileLists = array_map(function ($item) use ($nonMandatoryFileLists, $document) {
                        if (!in_array(strtolower($document->file_type), $item)) {
                            return $item;
                        } else {
                            return [];
                        }
                    }, $nonMandatoryFileLists);
                }
            }
        }

        if ($mandatoryFileLists) {
            $mandatoryFileLists = array_merge($mandatoryFileLists, $nonMandatoryFileLists);
            $data = array_filter(array_map(function ($item) use ($nonMandatoryFileLists) {
                return ((in_array($item, array_keys($nonMandatoryFileLists)) ? '' : '* ') . ucwords(str_replace('_', ' ', $item)));
            }, array_keys(array_filter($mandatoryFileLists))));
            foreach ($data as $_dData) {
                if (!in_array(str_replace(' ', '_', strtolower($_dData)), array_keys($nonMandatoryFileLists))) {
                    if (!in_array(strtolower($_dData), array_keys($nonMandatoryFileLists))) {
                        return response()->json(['status' => 'FAIL', 'data' => $data]);
                    }
                }
            }
        }

        if ($multiStageDisbursement->canPartialDisbursement($application->offer_id, $application)) {
            $avanseProcessesDisbursement = $avanseProcesses->addDisbursementInstructionsTranches();
        } else {
            $avanseProcessesDisbursement = $avanseProcesses->addDisbursementInstructions();
        }

        if (!is_array($avanseProcessesDisbursement) && is_int($avanseProcessesDisbursement)) {
            return response()->json(['status' => 'OK', 'avanse_disbursement_id' => $avanseProcessesDisbursement]);
        }

        return response()->json(['status' => 'FAIL', 'data' => $avanseProcessesDisbursement]);
    }

    public function refundDisbursement()
    {

        $PaymentTransaction = PaymentTransaction::with(['application' => function ($query) {
            $query->select(['id', 'name', 'merchant_id']);
        }])->with(['refundPayment' => function ($query) {
            $query->select(['id', 'payment_id', 'message', 'status']);
        }])->where('refund_maker_id', '>', 0)->wherenotNull('refund_maker_at')->whereNull('refunded_at')->whereNull('refunded_by')->get(['id', 'application_id', 'amount', 'refund_maker_id']);


        $merchant_ids = [];
        foreach ($PaymentTransaction as $item) {
            if(isset($item->application->merchant_id)){
                $merchant_ids[] = $item->application->merchant_id;
            }
        }

        $merchants = Merchant::whereIn('id', $merchant_ids)->get(['id', 'merchant_name']);

        $merchant_names = [];
        foreach ($merchants as $item) {
            $merchant_names[$item->id] = $item->merchant_name;
        }

        $applications = [];

        foreach ($PaymentTransaction as $item) {

            $job = JobProvider::where('application_id', $item->id)->where('from', 'refund_initiate')->first(['id']);

            $status = $item->refundPayment->status ?? "";
            if (isset($job->id)){
                $status = 'PENDING';
            }

            if (!isset($item->refundPayment->status) || (isset($item->refundPayment->status) && in_array($item->refundPayment->status, ['PENDING', 'REJECTED']))) {
                $applications[] = [
                    'tr_id' => $item->id,
                    'app_id' => $item->application_id,
                    'name' => $item->application->name,
                    'merchant_name' => $merchant_names[$item->application->merchant_id],
                    'amount' => $item->amount,
                    'error_message' => $item->refundPayment->message ?? "",
                    'refund_status' => $status,
                    'refund_maker_id' => $item->refund_maker_id
                ];
            }
        }


        $data = [
            'applications' => $applications,
        ];

        return view('admin.refund_disbursement', $data);
    }

    public function cancelRefund(){

        if($this->request->get('id')){
            PaymentTransaction::where('id', $this->request->get('id'))->where('application_id', $this->request->get('application_id'))->update(['refund_maker_at' => null, 'refund_maker_id' => null]);
        }

        return response()->json(['status' => 'FAIL', 'message' => 'Refund request cancelled']);

    }

    public function initiateRefundFromCashfree(Request $request)
    {

        $user_id = Auth::user()->id;

        if ($user_id && $request->get('id') && $request->get('application_id')) {
            $jobProvider = JobProvider::where('application_id', $request->get('id'))->where('from', 'refund_initiate')->first(['id']);
            if (!isset($jobProvider->id)) {
                $payload = [
                    'payload' => json_encode(['id' => $request->get('id'), 'application_id' => $request->get('application_id'),'auth_id' => $user_id]),
                    'from' => 'refund_initiate',
                    'application_id' => $request->get('id'),
                    'available_at' => Carbon::now()->toDateTimeString(),
                    'created_at' => Carbon::now()->toDateTimeString()
                ];
                JobProvider::insert($payload);

                return response()->json(['status' => 'OK', 'message' => 'Refund initiated. Please check slack for the update']);
            }
            return response()->json(['status' => 'FAIL', 'message' => 'Refund already initiated.']);
        }else{
            return response()->json(['status' => 'FAIL', 'message' => 'Failed to initiate the refund']);
        }
    }

    public function runRefundFromCashfree(){

        $paymentTransaction = PaymentTransaction::where('id', $this->request->get('id'))->where('application_id', $this->request->get('application_id'))->wherenotNull('refund_maker_at')->whereNull('refunded_at')->whereNull('refunded_by')->first(['amount']);

        $bank = Bank::where('application_id', $this->request->get('application_id'))->first();
        $application = ConsumerApplication::where('id', $this->request->get('application_id'))->first(['email', 'current_address_line_1','mobile_number']);

        $transferId = $this->request->get('application_id').$this->request->get('id').time();
        $payout = new PayoutCFAPI(new Request(['is_refund' => 1, 'id' => $this->request->get('application_id'), 'amount' => round($paymentTransaction->amount, 2), 'bankAccount' => $bank->account_number, 'ifsc' => $bank->ifsc_code, 'name' => $bank->name, 'transferId' => $transferId, 'address1' => $application->current_address_line_1, 'email' => $application->email, 'phone' => $application->mobile_number, 'remarks' => $this->request->get('application_id').' '.$this->request->get('id').' '.preg_replace('/[^A-Za-z0-9\-]/', '', $bank->name)]));
        $payout->isRefund = true;
        $payout->directTransfer();

        $message = '';
        if ($payout->error){
            $error = $payout->error->getData();
            $message = $error->message;
        }else if (isset($payout->response) && (isset($payout->response->message))){
            $message = $payout->response->message;
        }

        $RefundPayments = RefundPayments::where('payment_id', $this->request->get('id'))->first(['id']);
        if (isset($RefundPayments->id)){
            $refundPayment = RefundPayments::find($RefundPayments->id);

            $acknowledged = (isset($payout->response) && (isset($payout->response->data->acknowledged))) ? $payout->response->data->acknowledged : 0;

            $refundPayment->fill([
                'status' => $acknowledged == 1 ? 'SUCCESS' : 'PENDING',
                'referenceId' => (isset($payout->response) && (isset($payout->response->data->referenceId))) ? $payout->response->data->referenceId : '',
                'acknowledged' => $acknowledged,
                'utr' => (isset($payout->response) && (isset($payout->response->data->utr))) ? $payout->response->data->utr : '',
                'transferId' => $transferId,
                'message' => $message
            ]);

            $refundPayment->save();

            if($acknowledged){
                PaymentTransaction::where('id', $this->request->get('id'))->where('application_id', $this->request->get('application_id'))->update(['refunded_at' => Carbon::now()->toDateTimeString(), 'refunded_by' => $this->request->get('auth_id')]);
            }
        }else{
            $refundPayment = new RefundPayments();

            $acknowledged = (isset($payout->response) && (isset($payout->response->data->acknowledged))) ? $payout->response->data->acknowledged : 0;

            $refundPayment->fill([
                'application_id' => $this->request->get('application_id'),
                'payment_id' => $this->request->get('id'),
                'status' => $acknowledged == 1 ? 'SUCCESS' : 'PENDING',
                'referenceId' => (isset($payout->response) && (isset($payout->response->data->referenceId))) ? $payout->response->data->referenceId : '',
                'acknowledged' => $acknowledged,
                'utr' => (isset($payout->response) && (isset($payout->response->data->utr))) ? $payout->response->data->utr : '',
                'transferId' => $transferId,
                'message' => $message
            ]);

            $refundPayment->save();

            if(!$acknowledged) {
                $this->checkTransferStatusJob($this->request->get('application_id'), $transferId);
            }else{
                PaymentTransaction::where('id', $this->request->get('id'))->where('application_id', $this->request->get('application_id'))->update(['refunded_at' => Carbon::now()->toDateTimeString(), 'refunded_by' => $this->request->get('auth_id')]);
            }
        }

    }


    public function checkTransferStatusJob($id, $transferId){
        $jobProvider = JobProvider::where('application_id', $this->request->get('id'))->where('is_available', 1)->where('from', 'refund_initiate_status')->first(['id']);
        if (!isset($jobProvider->id)) {
            $payload = [
                'payload' => json_encode(['id' => $this->request->get('id'), 'application_id' => $id, 'auth_id' => $this->request->get('auth_id'), 'transferId' => $transferId]),
                'from' => 'refund_initiate_status',
                'application_id' => $this->request->get('id'),
                'available_at' => Carbon::now()->toDateTimeString(),
                'created_at' => Carbon::now()->toDateTimeString()
            ];
            JobProvider::insert($payload);
        }else{
            JobProvider::where('id', $jobProvider->id)->where('from', 'refund_initiate_status')->update(['available_at' => Carbon::now()->addMinutes(30)->toDateTimeString(), 'is_available' => 0]);
        }
    }

    public function checkTransferStatus($application_id, $payment_id){

        $payoutStatusData = RefundPayments::where('application_id', $application_id)->where('payment_id', $payment_id)->orderBy('created_at','desc')->first();

        $payoutStatus = new \stdClass();
        $payoutStatus->id = $payoutStatusData->id;
        $payoutStatus->referenceId = $payoutStatusData->referenceId;
        $payoutStatus->status = $payoutStatusData->acknowledged == 1 ? 'SUCCESS' : ($payoutStatusData->acknowledged == 0 ? 'PENDING' : 'FAILURE');

        $payout = new PayoutCFAPI(new Request(['id' => $application_id, 'transferId' => $this->request->get('transferId'), 'referenceId' => $payoutStatus->referenceId]));
        $payout->isRefund = true;
        $payoutResponseData = $payout->getTransferStatus();

        if($payoutResponseData['response'] && isset($payoutResponseData['response']->status) && $payoutResponseData['response']->status == 'SUCCESS'){
            $refundPayment = RefundPayments::find($payoutStatusData->id);

            $refundPayment->fill([
                'status' => $payoutResponseData['response']->status
            ]);
            $refundPayment->save();
        }else if(in_array($payoutResponseData['response']->status, ['FAILURE', 'FAILED', 'REJECTED'])){
            $refundPayment = RefundPayments::find($payoutStatusData->id);

            $refundPayment->fill([
                'status' => $payoutResponseData['response']->status,
                'message' => $payoutResponseData['response']->reason
            ]);
            $refundPayment->save();
            return true;

        }else if(!in_array($payoutResponseData['response']->status, ['FAILURE', 'FAILED'])){
            $this->checkTransferStatusJob($application_id, $this->request->get('transferId'));
            return true;
        }elseif($payoutResponseData['response']->status == 'FAILURE'){
            return true;
        }
    }

    public function getDisbursementAmountForLendboxLSP($application)
    {
        $advance_amount = $subvention_amount = $subvention_gst_amount = $downPayment = $pf_by_merchant = 0;
        $disbursement  = $application->approved_amount;
        $processing_fee_by_merchant = $this->isProcessingFeeApplicable($application);
        $is_cf_advance_amount = $this->isCFCollectingAdvance($application);

        if(!$is_cf_advance_amount){ // if advance amount not collected by CF
            $advance_amount = isset($application->emi) ? $application->emi->upfront_from_customer : 0;
            $disbursement -= $advance_amount; // advance amount collected by merchant
        }

        if ($processing_fee_by_merchant) {
            $pf_by_merchant = isset($application->emi) ? $application->emi->processing_fee : 0;
        }

        $charge_subvention_remaining_amount = $application->merchant && $application->merchant->charge_subvention_remaining_amount ? 1 : 0;
        if($charge_subvention_remaining_amount){
            $downPayment = $application->emi->upfront_from_customer;
        }
        $subventionAmnt = (($application->approved_amount - $downPayment) * $application->emi->subvention) / 100;
        $gstDetails = (new ConsumerDocument(new Request()))->getGSTDetails([
            'amount' => $subventionAmnt,
            'state' => (isset($application->merchant->state) && !empty($application->merchant->state)) ? $application->merchant->state : '',
        ]);

        if(is_array($gstDetails) && count($gstDetails) > 0 ){
            $subvention_amount = ($gstDetails[0]['amount']);
            foreach($gstDetails as $gstTax){
                $subvention_gst_amount += ($subvention_amount * $gstTax['tax_type']/100);
            }
        }

        return [
            'disbursement' => $disbursement,
            'processing_fee_by_merchant' => $pf_by_merchant,
            'subvention_amount' => $subvention_amount,
            'subvention_gst_amount' => round($subvention_gst_amount, 2),
            'advance_amount' => $advance_amount,
        ];
    }
}
