<?php
/**
 * Created by PhpStorm.
 * User: sunil
 * Date: 9/5/18
 * Time: 10:29 AM
 */

namespace App\Http\Controllers\Admin;

use App\BNPL;
use App\Events\V1\EventPostCreateCustomer;
use App\ApplicationEMICalculation;
use App\ApplicationEMICalculationLock;
use App\Avanse\Services\AvanseServices;
use App\CampaignsJobProvider;
use App\Console\Commands\BasicReminders;
use App\ConsumerApplicationElement;
use App\ConsumerApplication;
use App\DisbursementLogs;
use App\EmiPayment;
use App\Exports\Exporter;
use App\FinBit;
use App\FOIR;
use App\Http\Controllers\Controller;
use App\JobProvider;
use App\Jobs;
use App\Lenders;
use App\LoanManagement;
use App\Logging\CloudWatchLoggerFactory;
use App\Merchant;
use App\MerchantOffers;
use App\MultiStageDisbursement;
use App\PaymentEmi;
use App\PaymentTransaction;
use App\ProductOffers;
use App\ProFormaInvoice;
use App\PromiseToPay;
use App\Slack;
use App\DecisionTable;
use App\User;
use Carbon\Carbon;
use function Composer\Autoload\includeFile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Session;
use Maatwebsite\Excel\Facades\Excel;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class EMICalculation extends Controller
{

    private $request;
    public $loan_amount = 0;
    public $call_from_edit = false;
    public $merchant_id = 0;
    public $product_id = 0;
    private $merchant_offer_id = 0;
    private $category_id = 0;
    private $interest_type_id = 0;
    private $emi_amount = 0;
    private $application_id = 0;
    private $is_calculated_once = 0;
    public $isProcessingFeeApplicable = null;

    /**
     * @var mixed
     */
    private $net_loan_amount = 0;

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

    public function index()
    {
        $data['merchants'] = Merchant::with('merchant_category_many')->where('is_guest_active', 1)->where('status','active')->orderBy('merchant_name')->get(['id', 'merchant_name', 'category_id']);
        $data['interest_types'] = MerchantController::$interest_types;
        return view('admin.emi.index_v1', $data);
    }

    public function showEMIS(){


        $current_date = Carbon::now()->toDateString();
        $source = $this->request->get('source') ?? false;
        $isExported = $this->request->get('paymentfile') ?? ($this->request->get('export') ?? false);
        if ($isExported){
            $source = false;
        }

        if($this->request->has('export') && !$this->request->has('job_queue')){
            $jobs = new CampaignsJobProvider();
            $jobs->from = 'export_emis';
            $data = $this->request->input();
            unset($data['source']);
            $data['job_queue'] = 1;
            $data['mail'] = Auth::user()->email;
            $jobs->payload = json_encode($data);
            $jobs->available_at = Carbon::now()->toDateTimeString();
            $jobs->application_id = 181;
            $jobs->created_at = Carbon::now()->toDateTimeString();
            $jobs->is_available = 0;
            $jobs->save();
            Session::flash('success', 'You will receive an email in sometime');
            return redirect()->back();
        }

        if($this->request->has('paymentfile') && !$this->request->has('job_queue')){
            $jobs = new CampaignsJobProvider();
            $jobs->from = 'export_payment_file';
            $data = $this->request->input();
            unset($data['source']);
            $data['job_queue'] = 1;
            $data['paymentfile'] = 1;
            $data['mail'] = Auth::user()->email;
            $jobs->payload = json_encode($data);
            $jobs->available_at = Carbon::now()->toDateTimeString();
            $jobs->application_id = 181;
            $jobs->created_at = Carbon::now()->toDateTimeString();
            $jobs->is_available = 0;
            $jobs->save();
            Session::flash('success', 'You will receive an email in sometime');
            return redirect()->back();
        }


        if($this->request->has('ovderdue')){

            if(!$this->request->has('job_queue')) {
                $jobs = new CampaignsJobProvider();
                $jobs->from = 'export_overdue_emis';
                $data = $this->request->input();
                unset($data['source']);
                $data['job_queue'] = 1;
                $data['mail'] = Auth::user()->email;
                $jobs->payload = json_encode($data);
                $jobs->available_at = Carbon::now()->toDateTimeString();
                $jobs->application_id = 181;
                $jobs->created_at = Carbon::now()->toDateTimeString();
                $jobs->is_available = 0;
                $jobs->save();
                Session::flash('success', 'You will receive an email in sometime');
                return redirect()->back();
            }


            $loan_management = new LoanManagement();
            $data = $loan_management->getPaymentDueHistory(0,"",0,1,0,array(),1);

            $exporter[] = ['ID','Name','Merchant Name','Lender Name','Email','Phone','Amount','Last EMI Date','UMRN','Frequency','Mandate Amount','Collection Executive','Last Payment Date','Last Payment Amount','Overdue Amount', 'Mode'];

            foreach ($data as $application_id=>$application){
                    $exporter[] = [
                        'id' => $application_id,
                        'name' => $application['applicant_name'],
                        'merchant_name' => $application['merchant_name'],
                        'lender' => $application['lender_name'],
                        'email' => $application['applicant_email'],
                        'phone' => $application['applicant_number'],
                        'amount' => $this->getAmountByMandate($application),
                        'last_emi_date' => $application['last_emi_date'],
                        'umrn' => isset($application['mandate']->umrn) ? $application['mandate']->umrn : "",
                        'frequency' => isset($application['mandate']->frequency) ? (($application['mandate']->frequency == 'M') ? 'Monthly' : 'As and When Presented') : "",
                        'mandate_amount' => isset($application['mandate']->mandate_amount) ? $application['mandate']->mandate_amount : 0,
                        'collection_executive' => isset($application['collection_executive']) ? $application['collection_executive'] : '',
                        'last_payment_date' => $application['last_payment_date'],
                        'last_payment_amount' => $application['last_payment_amount'],
                        'overdue_amount' => $application['overdue_amount'],
                        'Mode' =>isset($application['mandate']->mode) ? $application['mandate']->mode : ''
                    ];
            }
            //$request = new Request(['data'=>$exporter,'sheet'=>'Sheet1']);
            //return Excel::download((new Exporter($request)), 'Over_EMI_'.date('Y-m-d').'.xls');


            $file = time().'_OverDue_Summary_'.date('Y-m-d').'.xlsx';
            $request = new Request(['data'=>$exporter,'sheet'=>'Sheet1']);
            //return Excel::download((new Exporter($request)), $file);

            Excel::store((new Exporter($request)), $file);

            $mail = $this->request->get('mail');
            Mail::send('emails.reminders.basic_reminder',
                ['body'=>'Over Due Summary Data']
                , function ($message) use ($file, $mail) {
                    $message->to([$mail])->subject('Over Due Summary '. Carbon::now()->toDateString());
                    $message->attachData(file_get_contents(storage_path().'/app/'.$file), $file);
                });

            if (file_exists(storage_path().'/app/'.$file)){
                unlink(storage_path().'/app/'.$file);
            }
            return false;

        }

        $status_array = ['disbursed','nach registered'];
        $data['merchants'] = Merchant::with('merchant_category_many')->where('is_guest_active', 1)->where('status','active')->get(['id', 'merchant_name', 'category_id']);
        $data['lenders'] = Lenders::all();

        $from_date = '';
        $responseData = [];
            $from_date = ($this->request->has('from_date') && !empty($this->request->get('from_date'))) ? Carbon::createFromFormat('Y-m-d',$this->request->get('from_date'))->toDateString() : Carbon::now()->toDateString();
            $keyword = $this->request->get('keyword');
            $data['lender_id'] = $this->request->get('lender_id');
            $data['merchant_id'] = $this->request->get('merchant_id');


            /*ConsumerApplication::setEmiDate($from_date);
            $dates = EmiPayment::where('emi_date', $from_date)->get(['application_id']);
            $datesIds = [];
            foreach ($dates as $dateItem){
                if(!in_array($dateItem->application_id, $datesIds)) {
                    $datesIds[] = $dateItem->application_id;
                }
            }*/

            if(!$this->request->has('paymentfile') || !$this->request->has('export') || !$this->request->has('ovderdue')) {
                if(!$source){
                    //$withArray = ['merchant', 'advisor', 'lender', 'bank_details', 'proFormaInvoice', 'monthlymandate', 'fullmandate', 'emi', 'emi_payment', 'application_element.collection_executive'];
                    $application = ConsumerApplication::with('merchant', 'advisor', 'lender', 'bank_details', 'emi', 'proFormaInvoice', 'monthlymandate', 'fullmandate', 'emi_payment', 'application_element.collection_executive')
                        ->whereHas('emi_payment', function($q) use ($from_date){
                            $q->where('emi_date', $from_date);
                        });
                }else {
                    //$withArray = ["'merchant'","'lender'"];
                    $application = ConsumerApplication::with('merchant', 'lender')
                        ->whereHas('emi_payment', function($q) use ($from_date){
                            $q->where('emi_date', $from_date);
                        })->whereHas('application_element', function($q) use ($from_date){
                            $q->whereNull('foreclosure_date');
                        });
                }

                //$application = ConsumerApplication::with(implode(',', $withArray))->whereIn('id', $datesIds);

                if ($keyword) {
                    $application = $application->where(function ($query) use ($keyword) {
                        if ($keyword) {
                            $query->where('name', 'like', '%' . $keyword . '%')
                                ->orWhere('email', 'like', '%' . $keyword . '%')
                                ->orWhere('mobile_number', 'like', '%' . $keyword . '%');
                        }
                    });
                }
                if ($data['lender_id']) {
                    $application = $application->where('lender_id', $data['lender_id']);
                }
                if ($data['merchant_id']) {
                    $application = $application->where('merchant_id', $data['merchant_id']);
                }

                $applications = $application->whereNull('is_deleted')->whereIn('consumer_application.state', $status_array)->groupBy('id');

                if ($this->request->has('paymentfile') || $this->request->has('export') || $this->request->has('ovderdue')){
                    //$applications = $applications->get();
                    $applications = $applications->paginate(10);
                }else{
                    $applications = $applications->paginate(10);
                }

                $data['applications'] = $applications;
                foreach ($applications as $application) {
                    if($application->emi_payment) {
                        if (!$source) {
//                    if($application->id  == 468){
//                        return(array) $application;
//                    }
//                $response = $this->generateDues($application->id, $from_date, false);
//                $emiData = array_filter($response['payload'], function ($element) use ($from_date) { return ($element['available_at'] == $from_date); } );
//                $emiData = array_values($emiData);
                            //if(isset($emiData[0])) {
                            $umrn = "";
                            $nach_status = 'Pending';
                            if (isset($application->monthlymandate->umrn) && !empty($application->monthlymandate->umrn) && $application->monthlymandate->umrn != "0") {
                                if (isset($application->monthlymandate->mode) && $application->monthlymandate->mode != 'lotuspay') {
                                    $umrn = $application->monthlymandate->umrn;
                                }
                                $nach_status = 'Active';
                            }
                            if ($umrn == "" && isset($application->fullmandate->umrn) && !empty($application->fullmandate->umrn) && $application->fullmandate->umrn != "0") {
                                if (isset($application->fullmandate->mode) && $application->fullmandate->mode != 'lotuspay') {
                                    $umrn = $application->fullmandate->umrn;
                                }
                                $nach_status = 'Active';
                            }

                            if (isset($application->proFormaInvoice->loan_application_no) && !empty($application->proFormaInvoice->loan_application_no)) {
                                $loan_application_id = $application->proFormaInvoice->loan_application_no;
                            } else {
                                $type = 7;
                                if ($application->merchant_id == 5026) {
                                    $type = 8;
                                }
                                if (strlen($application->id) < $type) {
                                    $diff = $type - strlen($application->id);
                                    $concatstring = "";
                                    for ($i = 0; $i < $diff; $i++) {
                                        $concatstring = $concatstring . "0";
                                    }
                                }
                                $loan_application_id = $application->merchant->slug . $concatstring . $application->id;
                            }

                            $emiAmount = isset($application->emi_payment[0]->emi_amount) ? $application->emi_payment[0]->emi_amount : 0;
                            if ($application->emi && $application->emi->emi && $application->emi->emi < $emiAmount) {
                                $moratorium = $emiAmount - $application->emi->emi;
                                $emiAmount -= $moratorium;
                            }

                            if ($application->emi && $application->emi->offer && $application->emi->offer->processing_fee_first_emi && $application->emi->processing_fee) {
                                $emiPayment = PaymentTransaction::where('application_id', $application->id)->where('payment_for', 'processing_fee')->whereNull('is_deleted_at')->first(['id']);
                                if (!isset($emiPayment->id)) {
                                    $emiAmount = $emiAmount + $application->emi->processing_fee;
                                }
                            }


                            $emiData = array('is_error' => isset($application->bank_details->id) ? (isset($application->proFormaInvoice->id) ? 0 : 2) : 1, 'id' => $application->id, 'name' => $application->name, 'email' => $application->email, 'phone' => $application->mobile_number, 'merchant_name' => isset($application->merchant->merchant_name) ? $application->merchant->merchant_name : '', 'collection_executive' => isset($application->application_element) && isset($application->application_element->collection_executive) ? $application->application_element->collection_executive->name : '', 'lender_name' => isset($application->lender->name) ? $application->lender->name : '', 'nach_status' => $nach_status, 'umrn' => $umrn, 'loan_application_id' => $loan_application_id, 'amount_payable' => '15000', 'first_emi_date' => isset($application->emi->emi_date) ? date('d-m-Y', strtotime($application->emi->emi_date)) : "", 'advisor' => isset($application->advisor->name) ? $application->advisor->name : "", 'emi_amount' => $emiAmount, 'city' => $application->current_address_city, 'state' => $application->current_address_state, 'co_applicant_name' => $application->co_applicant_name, 'co_applicant_number' => $application->co_applicant_mobile_number);
                            $responseData[] = $emiData;
                            //}

                        } else {
                            $responseData[] = ['is_error' => 0, 'merchant_name' => $application->merchant->merchant_name, 'name' => $application->name, 'lender_name' => $application->lender->name, 'id' => $application->id];
                        }
                    }
                }
            }

        $data['emis'] = $responseData;

        $data['from_date'] = $from_date;

            if ($source){
                return view('admin.emi.show', $data);
            }

        if($this->request->has('export')){
            $exporter[] = ['ID','Agreement Number','Name', 'Co Applicant Name', 'Co Applicant Number','Merchant Name','Lender Name','Email','Phone','Amount',
                'First EMI Date','Nach Status','Advisor','Collection Executive', 'Current City', 'Current State','Paid Amount',
                'PTP Date', 'PTP Tagged By','Last Payment Date','Overdue Amount', 'Mode'];

            $exportData = DB::select("select ca.id,pro.loan_application_no, ca.name,
       ca.co_applicant_name,
       ca.co_applicant_mobile_number,
       m.merchant_name,
       l.name as lender_name,
       ca.email,
       ca.mobile_number,
       emi_payments.emi_amount, emi_payments.pre_emi_amount, ec.emi_date,
       (select mandate.status from mandate where consumer_application_id = emi_payments.application_id and mandate.status in ('active', 'accepted') and umrn is not null limit 1) as mandate_status,
       (select mandate.mode from mandate where consumer_application_id = emi_payments.application_id and mandate.status in ('active', 'accepted') and umrn is not null limit 1) as mandate_mode,
       (select status_logs.created_at from status_logs where status_logs.application_id = ca.id and status_logs.status in ('disbursed') order by created_at desc limit 1) as disbursed_date,
       u.name as advisor_name,
       (select name from users where id = cae.collection_advisor) as collection_advisor,
       ca.current_address_city,
       ca.current_address_state,
       (select sum(amount) from payment_transactions where application_id = ca.id) as paid_amount,
       ptp.date as ptp_date,
       (select name from users where id = ptp.user_id limit 1) as ptp_name,
       (select payment_date from payment_transactions where application_id = ca.id and payment_for = 'EMI' order by id desc limit 1) as last_payment_date,
       cae.amount_over_due
from emi_payments
         left join consumer_application ca on emi_payments.application_id = ca.id
         left join consumer_application_element cae on emi_payments.application_id = cae.application_id
         left join users u on ca.created_by = u.id
         left join merchant m on ca.merchant_id = m.id
         left join lenders l on ca.lender_id = l.id
         left join emi_calculation ec on ec.application_id = ca.id
         left join pro_forma_invoice pro on ca.id = pro.application_id
         left join promise_to_pay ptp on ca.id = ptp.application_id
where emi_payments.emi_date = '".$from_date."' and ca.state in ('disbursed','nach registered') and cae.foreclosure_date is null and is_deleted is null");

            /*foreach ($data['emis'] as $emi){
                $lastAmountPaid = PaymentTransaction::where('application_id', $emi['id'])->where('payment_for','EMI')->orderBy('id','desc')->first();
                $emiPayment = EmiPayment::with('transaction','application_element')->where('application_id', $emi['id'])->where('emi_date', $from_date)->first();
                $promiseToPay = PromiseToPay::with('user')->where('application_id', $emi['id'])->orderBy('created_at','desc')->first();
                $payment_date = '';
                $payment_received = 0;
                $last_payment_date = '';
                $last_payment_amount = 0;
                $total_overdue_amount = 0;
                if($emiPayment->transaction){
                    foreach ($emiPayment->transaction as $_item){
                        $payment_date = $_item->payment_date;
                        $payment_received += $_item->amount;
                    }
                }
                if($lastAmountPaid){
                    $last_payment_date = $lastAmountPaid->payment_date;
                    $last_payment_amount = $lastAmountPaid->amount;
                }
                $total_overdue_amount = $emiPayment->application_element->amount_over_due;

                $exporter[] = [
                            'id' => $emi['id'],
                            'agreement_number' => $emi['loan_application_id'],
                            'name' => $emi['name'],
                            'co_applicant_name' => $emi['co_applicant_name'],
                            'co_applicant_number' => $emi['co_applicant_number'],
                            'merchant_name' => $emi['merchant_name'],
                            'lender' => $emi['lender_name'],
                            'email' => $emi['email'],
                            'phone' => $emi['phone'],
                            'amount' => $emi['emi_amount'],
                            'first_emi_date' => $emi['first_emi_date'],
                            'nach_status' => $emi['nach_status'],
                            'Advisor' => $emi['advisor'],
                            'collection_executive' => $emi['collection_executive'],
                            'city' => $emi['city'],
                            'state' => $emi['state'],
                            'PaymentDate' => $payment_date,
                            'paid_amount' => $payment_received,
                            'ptp_date' => $promiseToPay && $promiseToPay->date ? $promiseToPay->date : '',
                            'ptp_user' => $promiseToPay && $promiseToPay->user ? $promiseToPay->user->name : '',
                            'last_payment_date' => $last_payment_date,
                            'last_payment_amount' => $last_payment_amount,
                            'overdue_amount' => $total_overdue_amount,
                ];
            }*/

            $processedIds = [];

            foreach($exportData as $exportDataItem) {

                if(!in_array($exportDataItem->id, $processedIds)) {


                    $emiDay = Carbon::parse($exportDataItem->disbursed_date)->day;

                    if($exportDataItem->emi_date >= $current_date) {
                        if ($emiDay >= 1 && $emiDay <= 4) {
                            $emi_amount = $exportDataItem->emi_amount + round($exportDataItem->pre_emi_amount);
                        } else if ($emiDay == 5) {
                            $emi_amount = $exportDataItem->emi_amount;
                        } else {
                            $emi_amount = (empty($exportDataItem->emi_amount) || $exportDataItem->emi_amount == 0 || $exportDataItem->emi_amount == "") ? ($exportDataItem->pre_emi_amount > 0 ? round($exportDataItem->pre_emi_amount) : $exportDataItem->emi_amount) : $exportDataItem->emi_amount;
                        }
                    }else{
                        $emi_amount = $exportDataItem->emi_amount;
                    }


                    $processedIds[] = $exportDataItem->id;
                    $exporter[] = [
                        'id' => $exportDataItem->id,
                        'agreement_number' => $exportDataItem->loan_application_no,
                        'name' => $exportDataItem->name,
                        'co_applicant_name' => $exportDataItem->co_applicant_name,
                        'co_applicant_number' => wall_decrypt($exportDataItem->co_applicant_mobile_number),
                        'merchant_name' => $exportDataItem->merchant_name,
                        'lender' => $exportDataItem->lender_name,
                        'email' => wall_decrypt($exportDataItem->email),
                        'phone' => wall_decrypt($exportDataItem->mobile_number),
                        'amount' => $emi_amount,
                        'first_emi_date' => $exportDataItem->emi_date,
                        'nach_status' => $exportDataItem->mandate_status,
                        'Advisor' => $exportDataItem->advisor_name,
                        'collection_executive' => $exportDataItem->collection_advisor,
                        'city' => $exportDataItem->current_address_city,
                        'state' => $exportDataItem->current_address_state,
                        'paid_amount' => $exportDataItem->paid_amount,
                        'ptp_date' => $exportDataItem->ptp_date,
                        'ptp_user' => $exportDataItem->ptp_name,
                        'last_payment_date' => $exportDataItem->last_payment_date,
                        //'last_payment_amount' => $exportDataItem->last_payment_amount,
                        'overdue_amount' => $exportDataItem->amount_over_due,
                        'mode'=>$exportDataItem->mandate_mode
                    ];
                }
            }

            $file = time().'_EMI_Summary_'.$from_date.'.xlsx';
            $request = new Request(['data'=>$exporter,'sheet'=>'Sheet1']);
            //return Excel::download((new Exporter($request)), $file);

            Excel::store((new Exporter($request)), $file);

            $mail = $this->request->get('mail');
            Mail::send('emails.reminders.basic_reminder',
                ['body'=>'EMI Summary Data']
                , function ($message) use ($file, $mail) {
                    $message->to([$mail])->subject('EMI Summary '. Carbon::now()->toDateString());
                    //$message->cc(['imran@creditfair.in']);
                    $message->attachData(file_get_contents(storage_path().'/app/'.$file), $file);
                });

            if (file_exists(storage_path().'/app/'.$file)){
                unlink(storage_path().'/app/'.$file);
            }
            return false;
        }



        if($this->request->has('paymentfile')){
            if($data['lender_id'] == 1){
                $exporter[] = ['Name','UserNumber','Date','UMRN','Amount','PaymentDate','Paid Amount', 'Mode'];

                $queryData = DB::select("select name, (select mandate.umrn, mandate.mode from mandate where consumer_application_id = ep.application_id and mandate.status in ('active', 'accepted') and umrn is not null limit 1) as umrn
        , emi_amount,
           (select payment_date from payment_transactions where application_id = ep.application_id and payment_for = 'EMI' order by id desc limit 1) as PaymentDate,
           (select sum(amount) from payment_transactions where ep.application_id = payment_transactions.application_id) as PaidAmount
    from emi_payments as ep
        left join consumer_application ca on ca.id = ep.application_id
        left join consumer_application_element cae on cae.id = ep.application_id
        where emi_date = '".$from_date."' and cae.foreclosure_date is null and state in ('disbursed','nach registered')");


                /*foreach ($data['emis'] as $emi){
                    $emiPayment = EmiPayment::with('transaction')->where('application_id', $emi['id'])->where('emi_date', $from_date)->first();
                    $payment_date = '';
                    $payment_received = 0;
                    if($emiPayment->transaction){
                        foreach ($emiPayment->transaction as $_item){
                            $payment_date = $_item->payment_date;
                            $payment_received += $_item->amount;
                        }
                    }

                    if($emi['umrn'] != '') {
                        $exporter[] = [
                            'Name' => $emi['name'],
                            'UserNumber' => 'NACH00000000019187',
                            'Date' => date('d-m-Y', strtotime($from_date)),
                            'UMRN' => $emi['umrn'],
                            'Amount' => $emi['emi_amount'],
                            'PaymentDate' => $payment_date,
                            'paid_amount' => $payment_received,
                        ];
                    }
                }*/

                foreach($queryData as $queryDataItem) {
                    if($queryDataItem->umrn != '') {
                        $exporter[] = [
                            'Name' => $queryDataItem->name,
                            'UserNumber' => 'NACH00000000019187',
                            'Date' => date('d-m-Y', strtotime($from_date)),
                            'UMRN' => $queryDataItem->umrn,
                            'Amount' => $queryDataItem->emi_amount,
                            'PaymentDate' => $queryDataItem->PaymentDate,
                            'paid_amount' => $queryDataItem->PaidAmount,
                            'mode' => $queryDataItem->mode
                        ];
                    }
                }

                $request = new Request(['data'=>$exporter,'sheet'=>'Sheet1']);
                return Excel::download((new Exporter($request)), 'NACH_TXN_FILE_NEW.xlsx');
            }else{

                if(!$this->request->has('job_queue')) {
                    $jobs = new CampaignsJobProvider();
                    $jobs->from = 'export_payment_file';
                    $data = $this->request->input();
                    unset($data['source']);
                    $data['job_queue'] = 1;
                    $data['paymentfile'] = 1;
                    $data['mail'] = Auth::user()->email;
                    $jobs->payload = json_encode($data);
                    $jobs->available_at = Carbon::now()->toDateTimeString();
                    $jobs->application_id = 181;
                    $jobs->created_at = Carbon::now()->toDateTimeString();
                    $jobs->is_available = 0;
                    $jobs->save();
                    Session::flash('success', 'You will receive an email in sometime');
                    return redirect()->back();
                }

                $exporter[] = ['Name','UserNumber','Date','UMRN','Amount','ReferenceNo','PaymentDate','Paid Amount','Last Payment Date','Last Payment Amount','Overdue Amount', 'Mode'];
//((emi_payments.emi_amount + IFNULL((select insurance_premium_amount from pro_forma_invoice as pro where pro.application_id = ca.id and pro.insurance_premium_applicable = 1 and pro.insurance_premium_by_merchant = 1), 0)) - IFNULL((select ppt.amount from payment_transactions as ppt where ppt.application_id = ca.id and payment_for = 'insurance_fee' limit 1), 0)) as emi_amount,
                $dataPaymentFiles = DB::select("select emi_payments.application_id, ca.lender_id, ca.name,emi_payments.emi_date,
       (select mandate.umrn from mandate where consumer_application_id = emi_payments.application_id and mandate.status in ('active', 'accepted') and (umrn != '' || umrn != 0) limit 1) as umrn,
       (select mandate.mode from mandate where consumer_application_id = emi_payments.application_id and mandate.status in ('active', 'accepted') and (umrn != '' || umrn != 0) limit 1) as mode,
       emi_payments.emi_amount,
       emi_payments.pre_emi_amount,
       (select status_logs.created_at from status_logs where status_logs.application_id = ca.id and status_logs.status in ('disbursed') order by created_at desc limit 1) as disbursed_date,
       pro.loan_application_no,
       (select payment_date from payment_transactions where application_id = emi_payments.application_id and payment_for = 'EMI' order by id desc limit 1) as last_payment_date,
       (select sum(amount) from payment_transactions where application_id = ca.id and payment_for = 'EMI') as paid_amount,
       (select amount from payment_transactions where application_id = ca.id and payment_for = 'EMI' order by id desc limit 1) as last_payment_amount,
       cae.amount_over_due from emi_payments
left join consumer_application ca on emi_payments.application_id = ca.id
left join emi_calculation ec on ec.application_id = ca.id
left join consumer_application_element cae on cae.application_id = ca.id
left join pro_forma_invoice pro on emi_payments.application_id = pro.application_id
where emi_payments.emi_date = '".$from_date."' and ca.state in ('disbursed','nach registered') and (select mandate.status from mandate where consumer_application_id = emi_payments.application_id and mandate.status in ('active', 'accepted') and umrn is not null limit 1) is not null and cae.foreclosure_date is null and is_deleted is null;");

                /*foreach ($data['emis'] as $emi){
                    $emiPayment = EmiPayment::with('transaction','application_element')->where('application_id', $emi['id'])->where('emi_date', $from_date)->first();
                    $lastAmountPaid = PaymentTransaction::where('application_id', $emi['id'])->where('payment_for','EMI')->orderBy('id','desc')->first();
                    $payment_date = '';
                    $payment_received = 0;
                    $last_payment_date = '';
                    $last_payment_amount = 0;
                    $total_overdue_amount = 0;
                    if($emiPayment->transaction){
                        foreach ($emiPayment->transaction as $_item){
                            $payment_date = $_item->payment_date;
                            $payment_received += $_item->amount;
                        }
                    }
                    if($lastAmountPaid){
                        $last_payment_date = $lastAmountPaid->payment_date;
                        $last_payment_amount = $lastAmountPaid->amount;
                    }
                    $total_overdue_amount = $emiPayment->application_element->amount_over_due;

                    if($emi['umrn'] != '') {
                        $exporter[] = [
                            'Name' => $emi['name'],
                            'UserNumber' => $data['lender_id'] == 2 ? 'NACH00000000021321' : ($data['lender_id'] == AvanseServices::$lender_id ? _env('LOTUSPAY_UTILITYCODE_AV') : ''),
                            'Date' => date('d-m-Y', strtotime($from_date)),
                            'UMRN' => $emi['umrn'],
                            'Amount' => $emi['emi_amount'],
                            'ReferenceNo' => $emi['loan_application_id'],
                            'PaymentDate' => $payment_date,
                            'paid_amount' => $payment_received,
                            'last_payment_date' => $last_payment_date,
                            'last_payment_amount' => $last_payment_amount,
                            'overdue_amount' => $total_overdue_amount,
                        ];
                    }
                }*/


                $dataPaymentFilesIds = [];


                foreach($dataPaymentFiles as $dataPaymentFileItem){
                    if(!in_array($dataPaymentFileItem->application_id, $dataPaymentFilesIds)) {
                        $dataPaymentFilesIds[] = $dataPaymentFileItem->application_id;


                        $emiDay = Carbon::parse($dataPaymentFileItem->disbursed_date)->day;

                        if($dataPaymentFileItem->emi_date >= $current_date) {
                            if ($emiDay >= 1 && $emiDay <= 4) {
                                $emi_amount = $dataPaymentFileItem->emi_amount + round($dataPaymentFileItem->pre_emi_amount);
                            } else if ($emiDay == 5) {
                                $emi_amount = $dataPaymentFileItem->emi_amount;
                            } else {
                                $emi_amount = (empty($dataPaymentFileItem->emi_amount) || $dataPaymentFileItem->emi_amount == 0 || $dataPaymentFileItem->emi_amount == "") ? ($dataPaymentFileItem->pre_emi_amount > 0 ? round($dataPaymentFileItem->pre_emi_amount) : $dataPaymentFileItem->emi_amount) : $dataPaymentFileItem->emi_amount;
                            }
                        }else{
                            $emi_amount = $dataPaymentFileItem->emi_amount;
                        }


                        $exporter[] = [
                            'Name' => $dataPaymentFileItem->name,
                            'UserNumber' => $dataPaymentFileItem->lender_id == 2 ? 'NACH00000000021321' : ($dataPaymentFileItem->lender_id == AvanseServices::$lender_id ? _env('LOTUSPAY_UTILITYCODE_AV') : ''),
                            'Date' => date('d-m-Y', strtotime($from_date)),
                            'UMRN' => $dataPaymentFileItem->umrn,
                            'Amount' => $emi_amount,
                            'ReferenceNo' => $dataPaymentFileItem->loan_application_no,
                            'PaymentDate' => $dataPaymentFileItem->last_payment_date,
                            'paid_amount' => $dataPaymentFileItem->paid_amount,
                            'last_payment_date' => $dataPaymentFileItem->last_payment_date,
                            'last_payment_amount' => $dataPaymentFileItem->last_payment_amount,
                            'overdue_amount' => $dataPaymentFileItem->amount_over_due,
                            'mode' => $dataPaymentFileItem->mode
                        ];
                    }
                }

                $file = time().'HDFC ACH Debit file.xls';
                $request = new Request(['data'=>$exporter,'sheet'=>'Sheet1']);

                Excel::store((new Exporter($request)), $file);

                $mail = $this->request->get('mail');
                Mail::send('emails.reminders.basic_reminder',
                    ['body'=>'HDFC ACH Debit file']
                    , function ($message) use ($file, $mail) {
                        $message->to([$mail])->subject('HDFC ACH Debit '. Carbon::now()->toDateString());
                        $message->attachData(file_get_contents(storage_path().'/app/'.$file), $file);
                    });

                if (file_exists(storage_path().'/app/'.$file)){
                    unlink(storage_path().'/app/'.$file);
                }
                return false;

                //$request = new Request(['data'=>$exporter,'sheet'=>'Sheet1']);
                //return Excel::download((new Exporter($request)), 'HDFC ACH Debit file.xls');
            }
        }
        return view('admin.emi.show', $data);
    }

    public function getAmountByMandate($application){

        if (isset($application['mandate']->umrn) && !empty($application['mandate']->umrn) && $application['mandate']->umrn != "0") {
            if ($application['mandate']->collection == 'D'){
                return $application['mandate']->mandate_amount;
            }
            if($application['amount_due'] < $application['mandate']->mandate_amount){
                return $application['amount_due'];
            }else if($application['amount_due'] > $application['mandate']->mandate_amount){
                return $application['mandate']->mandate_amount;
            }
        }
        return $application['amount_due'];
    }

    public function updateEmiPayment($application_id,$amount_paid,$emi_date,$mode){

        $payable_amount = $this->calculatePayableAmount($application_id);
        if($payable_amount > 0) {
            $EMIPayments = EmiPayment::where('application_id', $application_id)->where('payment_status','!=','success')->wherenull('deleted_at')->get();
            if(isset($EMIPayment[0]->id)) {
                foreach ($EMIPayments as $EMIPayment){
                    $emi_payable = ($EMIPayment->emi_amount + $EMIPayment->bounce_charges + $EMIPayment->delay_penalty) - $EMIPayment->charges_waived;
                    if($emi_payable <= $amount_paid){
                        EmiPayment::where('id',$EMIPayment->id)->update(['state'=>"success",'payment_mode'=>$mode]);
                        $amount_paid = $amount_paid-$emi_payable;
                    }else{
                        if($EMIPayment->emi_amount <= $amount_paid){

                        }else{
                            EmiPayment::where('id',$EMIPayment->id)->update(['state'=>"partial",'payment_mode'=>$mode]);
                        }
                    }
                }
            }
        }
    }

    public function calculatePayableAmount($application_id){
        return 1000;
    }
    public function prepareCalculation()
    {
        $this->call_from_edit = $this->request->has('call_from_edit');
        $this->loan_amount = $this->request->get('loan_amount');
        $this->net_loan_amount = $this->request->get('net_loan_amount');
        $this->merchant_id = $this->request->get('merchant_id');
        $this->product_id = explode(',', $this->request->get('product_id'));
        $this->category_id = $this->request->get('category_id');
        $this->emi_amount = $this->request->get('emi_amount');
        $this->application_id = $this->request->get('application_id');

        $this->interest_type_id = $this->request->get('interest_type_id');
        $this->merchant_offer_id = $this->request->get('merchant_offer_id');
        if (!$this->merchant_offer_id) {
            $response = $this->getEMIsByMerchant();
            if($this->call_from_edit && isset($this->application_id) && $this->application_id != 0){
                $response = $this->getEligibleOffersV1($this->application_id, $response);
            }
            return response()->json($response, 200);
        }
        $response = $this->getEMIs($this->request->has('offer_obj') && $this->request->get('offer_obj') ? $this->request->get('offer_obj') : $this->setMerchantOffer());

        if($this->call_from_edit && isset($this->application_id) && $this->application_id != 0){
            $response = $this->getEligibleOffersV1($this->application_id, $response);
        }
        return response()->json($response, 200);
    }

    public function getEligibleOffers($id, $offers)
    {
        $tofOffers = DecisionTable::with('eligibleOffers')->where('application_id', $id)->where('status', 0)->get();
        $previous_applied_offer_record = ConsumerApplicationElement::where('application_id', $id)->first(['previous_applied_offer']);
        $current_offer = ConsumerApplication::where('id', $id)->first(['offer_id']);

        $current_offer_id = isset($current_offer->offer_id) ? $current_offer->offer_id : null;
        if ($tofOffers->isNotEmpty()) {
            $eligibleOfferIds = [];
            if(isset($current_offer_id)){
                $exists = false;
                foreach ($offers as $o) {
                    if (isset($o['id']) && $o['id'] == $current_offer_id) {
                        $exists = true;
                        break;
                    }
                }
                if($exists){
                    $eligibleOfferIds[] = $current_offer_id;
                    $only_applied = true;
                }
            }

            if(isset($previous_applied_offer_record->previous_applied_offer)){
                $eligibleOfferIds[] = $previous_applied_offer_record->previous_applied_offer;
            }
            foreach ($tofOffers as $offer) {
                if (isset($offer->eligibleOffers) && !empty($offer->eligibleOffers)) {
                    foreach ($offers as $o) {
                        if (isset($o['id']) && $o['id'] == $offer->eligibleOffers->id) {
                            $exists = true;
                            break;
                        }
                    }
                    if ($exists) {
                        $eligibleOfferIds[] = $offer->eligibleOffers->id;
                        $only_applied = false;
                    }
                }
            }

            if (!empty($eligibleOfferIds) && isset($only_applied) && !$only_applied) {
                // Filter only eligible offers
                $filteredOffers = array_filter($offers, function ($offer) use ($eligibleOfferIds) {
                    return in_array($offer['id'], $eligibleOfferIds);
                });

                return array_values($filteredOffers); // Reset array keys
            }
        }

        return $offers; // Return empty array if no eligible offers found
    }

    public function getEligibleOffersV1($id, $offers)
    {
        $tofOffers = DecisionTable::with('eligibleOffers')
            ->where('application_id', $id)
            ->where('status', 0)
            ->get();

        $previous_applied_offer_record = ConsumerApplicationElement::where('application_id', $id)
            ->value('previous_applied_offer');

        $current_offer_id = ConsumerApplication::where('id', $id)->value('offer_id');


        if ($tofOffers->isNotEmpty()) {
            $eligibleOfferIds = [];
            $only_applied = false;

            if (isset($current_offer_id)) {
                $offer_exists = collect($offers)->contains('id', $current_offer_id); // Checking if the current offer exists id TOF eligible Offers
                if ($offer_exists) {
                    $eligibleOfferIds[] = $current_offer_id;
                    $only_applied = true;
                }
            }

            if (isset($previous_applied_offer_record)) {
                $eligibleOfferIds[] = $previous_applied_offer_record;
            }

            foreach ($tofOffers as $offer) {
                if (isset($offer->eligibleOffers) && !empty($offer->eligibleOffers)) {
                    $exists = collect($offers)->contains('id', $offer->eligibleOffers->id);  // Checking if the tof offers exists in offers list
                    if ($exists) {
                        $eligibleOfferIds[] = $offer->eligibleOffers->id;
                        $only_applied = false;
                    }
                }
            }


            if (!empty($eligibleOfferIds) && !$only_applied) {
                // Filter only eligible offers
                $filteredOffers = array_filter($offers, function ($offer) use ($eligibleOfferIds) {  // filtering the eligiblle offers list out of the all
                    return in_array($offer['id'], $eligibleOfferIds);
                });

                return array_values($filteredOffers);
            }
        }

        return $offers;
    }

    public function getEMIsByMerchant()
    {
        $offers = MerchantOffers::with('disbursementOffersData')->where('merchant_id', $this->merchant_id)->where('status',1)->orderBy('tenure', 'asc')->get();
        if($this->product_id) {
            $prod_offers = ProductOffers::with('disbursementOffersData')->whereIn('product_id', $this->product_id)->whereNull('deleted_at')->get();
        }
        $emiCalculations = [];
        if(isset($prod_offers) && count($prod_offers) > 0){
            foreach ($prod_offers as $prod) {
                foreach ($offers as $offer) {
                    if($prod->offer_id == $offer->id ) {
                        $emiCalculations[] = $this->getEMIs($offer);
                    }
                }
            }
        }else{
            foreach ($offers as $offer) {
                $emiCalculations[] = $this->getEMIs($offer);
            }
        }

        return $emiCalculations;
    }

    public function setMerchantOffer()
    {
        return MerchantOffers::where('merchant_id', $this->merchant_id)->where('id', $this->merchant_offer_id)->where('status',1)->orderBy('tenure', 'asc')->first();
    }

    public function getEMIs($offer,$application_id = 0)
    {


        $processing_fee = isset($offer->processing_fee) && $offer->processing_fee ? $offer->processing_fee : 0;

        if(!$this->request->has('offer_obj')) {
            // Reject the application if the customer has applied for the loan before
            // if ($this->request->has('application_id') && (new ConsumerApplicationController())->isProcessingFeeApplicable($this->request->get('application_id'))) {
            //     $processing_fee = 0;
            // }
            if (!isset($this->isProcessingFeeApplicable)) {
                if ($this->request->has('application_id')) {
                    $controller = new ConsumerApplicationController();
                    $this->isProcessingFeeApplicable = $controller->isProcessingFeeApplicable($this->request->get('application_id'));
                } else {
                    $this->isProcessingFeeApplicable = false;
                }
            }

            if (isset($this->isProcessingFeeApplicable) && $this->isProcessingFeeApplicable == true) {
                $processing_fee = 0;
            }
        }
        $charge_subvention_remaining_amount = 0;

        if($this->request->has('charge_subvention_remaining_amount')){
            if($this->request->get('charge_subvention_remaining_amount')){
                $charge_subvention_remaining_amount = 1;
            }
        }else {
            if ($offer->merchant_id) {
                $merchant = Merchant::where('id', $offer->merchant_id)->first(['charge_subvention_remaining_amount', 'processing_fee_on_advance_amount']);
                if (isset($merchant->charge_subvention_remaining_amount) && $merchant->charge_subvention_remaining_amount) {
                    $charge_subvention_remaining_amount = 1;
                }
            }
        }

        $legal_charges = 0;
        $application = ConsumerApplication::with('proFormaInvoice', 'emi')->where('id', $this->application_id)->first();
        if($application){
            $legal_charges = (new DisbursementController(new Request()))->getLegalChargesAmount($application);
        }

        $processingfeeOnRemainingAmount = $merchant->processing_fee_on_advance_amount ?? 0;

        $emiCalculation = new \App\EMICalculation();
        $emiCalculation->appId = $this->request->get('application_id');
        $emiCalculation
            ->setDisbursementOffersData(
                isset($offer->disbursementOffersData) && is_object($offer->disbursementOffersData)
                    ? $offer->disbursementOffersData
                    : new stdClass()
            )
            ->setAnnualizedIrr((float)$offer->annualised_irr)
            ->setLoanAmount((float)$this->loan_amount)
            ->setNetLoanAmount((float)$this->net_loan_amount)
            ->setEmi((float)$this->emi_amount)
            ->setTenure($offer->tenure)
            ->setSlug($offer->slug)
            ->setOfferID($offer->id)
            ->setAdvanceEMI($offer->advance_emi)
            ->setInterestRate($offer->interest_rate)
            ->setSubvention($offer->subvention)
            ->setChargeSubventionRemainingAmount($charge_subvention_remaining_amount)
            ->setSubventionType(MerchantController::$subvention_types[$offer->subvention_type_id])
            ->setAdvanceType($offer->advance_type)
            ->setProcessingFeeType($offer->processing_fee_type)
            ->setProcessingFeeCollected($offer->processing_fee_collected)
            ->setProcessingFee($processing_fee)
            ->setLegalCharges($legal_charges)
            ->setProcessingFeesOnAdvanceAmount($processingfeeOnRemainingAmount,$processing_fee)
            // ->setProcessingFeesOnAdvanceAmount($processingfeeOnRemainingAmount)
            ->setInterestType($offer->interest_type_id)
            ->setPaymentFrequency($offer->payment_frequency)
            ->setDisbursementMethod($offer->disbursement_method)
            ->setApplicationId($this->application_id);
        return $emiCalculation->calculateEMI();
    }

    public function getPFBreakUpCalculations($id){
        $offer_detail = ConsumerApplication::with('activeOffer')->where('id',$id)->first();
        $processing_fee = isset($offer_detail->activeOffer->processing_fee) && $offer_detail->activeOffer->processing_fee ? $offer_detail->activeOffer->processing_fee : 0;
        $processing_fee_type = isset($offer_detail->activeOffer->processing_fee_type) && $offer_detail->activeOffer->processing_fee_type ? $offer_detail->activeOffer->processing_fee_type : 0;

        // Reject the application if the customer has applied for the loan before
        if ($this->request->has('application_id') && (new ConsumerApplicationController())->isProcessingFeeApplicable($this->request->get('application_id'))) {
            $processing_fee = 0;
        }


        switch ($processing_fee_type){
            case 'fixed_amount':
                break;
            case 'percentage':
                $processing_fee = round(($processing_fee / 100) * $this->loan_amount);
                break;
        }

        if($processing_fee) {
            $pf_calc = (new RiskController(new Request()))->getProcessingFee($id, $processing_fee, 0, true);
            return [
                'processing_fee' => $pf_calc['final_pf_amount'],
                'original_processing_fee' => $pf_calc['pf'],
                'pf_surcharge_percent' => $pf_calc['pf_surcharge_percent'],
                'pf_surcharge_amount' => $pf_calc['pf_surcharge_amount'],
                'pf_surcharge_gst' => $pf_calc['pf_surcharge_gst']
            ];
        }

        return [];
    }

    public function getRepaymentSchedule($schedule, $is_generate = true)
    {
        $emi = $schedule->emi->emi;
        $payable = $schedule->emi->payable_by_customer;
        $emi_remaining = $schedule->emi->remaining_emi - 1;
        $upFrontFromMerchant = $schedule->emi->upfront_from_customer;
        $processing_fee = $schedule->emi->processing_fee;
        $legal_charges = $schedule->emi->legal_charges;

        $insurance_premium_amount = 0;
        if(isset($schedule->proFormaInvoice) && isset($schedule->proFormaInvoice->insurance_premium_applicable) && $schedule->proFormaInvoice->insurance_premium_applicable == 1 && $schedule->proFormaInvoice->insurance_premium_by_merchant == 1){
            $insurance_premium_amount = $schedule->proFormaInvoice->insurance_premium_amount;
        }

        if($emi_remaining == -1){
            $emi_remaining = 0;
        }

        $last_emi = $payable - ($emi * $emi_remaining) - $upFrontFromMerchant - $processing_fee - $insurance_premium_amount - $legal_charges;
        $emis = [];
        for ($i = 0; $i < $emi_remaining; $i++) {
            $emis[] = $emi;
        }

        array_push($emis,$last_emi);
        $schedule->emi->emis = $emis;
        if(!$is_generate){
            return $schedule->emi;
        }
        $emiAdvanceTypes = $this->getAdvanceType($schedule);
        if(!isset($emiAdvanceTypes->advance_type)){
            return ['error' => 'Please update the merchant offer'];
        }
        $schedule->emi->advance_type = $emiAdvanceTypes->advance_type;
        $schedule->emi->processing_fee_type = $emiAdvanceTypes->processing_fee_type;
        $schedule->emi->offer_processing_fee = $emiAdvanceTypes->processing_fee;
        $schedule->emi->interest_type_id = $emiAdvanceTypes->interest_type_id;
        $schedule->emi->approved_amount = $schedule->approved_amount;
        $schedule->emi->processing_fee_by_merchant = $this->getProcessingFeeByMerchant($schedule);

        return $schedule->emi;
    }

    public function getProcessingFeeByMerchant($schedule)
    {
        $invoice = ProFormaInvoice::where('application_id', $schedule->id)->first(['processing_fee_by_merchant']);
        return isset($invoice->processing_fee_by_merchant) ? $invoice->processing_fee_by_merchant : 0;
    }

    public function getAdvanceType($schedule)
    {
        return MerchantOffers::find($schedule->emi->offer_id);
    }

    public function startReSchedule($application, $isReSchedule, $approved_amount, $data, $id){
        $due_amount = isset($data['due_amount']) && $data['due_amount'] > 0 ? $data['due_amount'] : 0;
        if($due_amount){
            $approved_data = ConsumerApplication::where('id',$id)->first(['approved_amount']);
            if(isset($approved_data->approved_amount)){
                $approved_amount = $approved_data->approved_amount;
                ConsumerApplication::where('id',$id)->update(['approved_amount'=>$due_amount]);
            }
        }

        if($isReSchedule == 1 && isset($data['tenure'])){
            ConsumerApplication::where('id',$id)
                ->update(['tenure' => $data['tenure']]);
        }

        $data = $application->toArray();
        unset($data['id']);


        if($this->ifThereIsChangeInEMI($id, $data)){
            $applicationLock = new ApplicationEMICalculationLock();
            $applicationLock->fill($data);
            $applicationLock->created_at = Carbon::now()->toDateTimeString();
            $applicationLock->re_scheduled_type = $isReSchedule;
            $applicationLock->re_scheduled_by = Auth::check() ? Auth::user()->id : ($data['user_id'] ?? 107);
            $applicationLock->approved_amount = $approved_amount;
            $applicationLock->save();
        }
    }

    public function generateEMI(Request $request, $id)
    {
        try {
            $data = ($this->request->all()) ? $this->request->all() : $this->request->request->all();

            $isReSchedule = $data['re_schedule_type'] ?? false;

            $application = ApplicationEMICalculation::where('application_id', $id)->first(['id', 'offer_id', 'pf_surcharge_percent']);
            $accounting = new AccountingController();
            $consumerController = new ConsumerApplicationController();

            $offer_id = $data['offer_id'] ?? ($application && $application->offer_id ? $application->offer_id : 0);
            $payment_frequency = 1;
            if ($offer_id) {
                $payment_frequency_data = MerchantOffers::where('id', $offer_id)->first();
                $payment_frequency = $payment_frequency_data->payment_frequency ?? $payment_frequency;
            }

            $application_status = ConsumerApplication::with('activeOffer')->where('id', $id)->first(['id','merchant_id', 'lender_id', 'offer_id']);
            $consumerController->saveLiabilityPercent($application_status, $id);

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

                $application = ApplicationEMICalculation::find($application->id);
                $consumerApplication = ConsumerApplication::where('id',$application->application_id)->first(['offer_id','approved_amount','state']);
                if(isset($data['offer_id']) && $consumerApplication->offer_id != $data['offer_id']){
                    ConsumerApplication::where('id',$application->application_id)->update(['offer_id'=>$data['offer_id']]);
                }

                if (str_contains($this->request->get('first_emi_date'), '00:00:00')) {
                    $emiDate = Carbon::parse($this->request->get('first_emi_date'))->toDateString();

                } else {
                    $emiDate = Carbon::createFromFormat('d/m/Y', $this->request->get('first_emi_date'))->toDateString();
                }

                $approved_amount = isset($consumerApplication->approved_amount) ? $consumerApplication->approved_amount : 0;
                if($isReSchedule){
                    $this->startReSchedule($application, $isReSchedule, $approved_amount, $data, $id);
                }else{
                    $dataInput = $data;
                    $this->lockThePreviousEMICalculation(array_merge($dataInput, ['application_id' => $id, 'status' => 1, 'emi_date' => $emiDate.' 00:00:00', 'user_id' => ($request->has('user_id') && !empty($request->get('user_id'))) ? $request->get('user_id') : ($request->request->has('user_id') && !empty($request->request->get('user_id')) ? $request->request->get('user_id') : 107)]), $approved_amount);
                }

                // for debugging
                if(!in_array(date('d', strtotime($emiDate)), [5, 18, 7, 07, 05])){
                    $userRo = User::where('id', 27)->first(['slack_id']); //sunil
                    $slack_id = isset($userRo->slack_id) && $userRo->slack_id ? [$userRo->slack_id] : [];
                    (new Slack(new Request(['title' => 'EMI Date Issue', 'fields' => ['Application ID' => $id, 'Date' => $emiDate, 'Data' => json_encode($data), 'Initiated By' => Auth::check() ? Auth::user()->name : ''], 'tagging' => $slack_id])))->send();
                    $data = ['status' => 'FAIL', 'message' => 'Failed to generated EMI. error - '. $emiDate.' is wrong'];
                    return response()->json($data, 200);
                }

                $application->application_id = $id;
                $application->status = 1;
                $application->emi_date = $emiDate;
                $application->fill($data);
                if ($consumerController->isProcessingFeeApplicable($id)) {
                    $application->processing_fee = 0;
                }
                $application->save();
                FOIR::where('application_id', $id)->where('AccountType', 'Credit Fair EMI')->update(['InstallmentAmount'=>$data['emi'], 'updated_at'=>Carbon::now()->toDateTimeString()]);
                $irr_data = $accounting->getIrrRate($id, $data);
                if($irr_data){
                    $irr_data = json_decode($irr_data);
                    $application->rate = isset($irr_data->rate) ? $irr_data->rate : 0;
                    $application->annualised_interest = isset($irr_data->annualised_interest) ? $irr_data->annualised_interest : 0;
                    $application->irr_rate = isset($irr_data->irr_rate) ? $irr_data->irr_rate : 0;
                    $application->annualised_irr = isset($irr_data->annualised_irr) ? $irr_data->annualised_irr : 0;
                    $application->save();

                    $accounting->MultiStageIRR($id);
                }
                if(isset($data['flag'])){
                    if(($consumerApplication->state == 'approved') || ($consumerApplication->state == 'disbursement checklist done') || ($consumerApplication->state == 'ready for disbursement')){
                        event(new EventPostCreateCustomer($application->application_id,'createCamReportCommand'));
                    }
                }

            } else {

                $emiDate = Carbon::createFromFormat('d/m/Y', $this->request->get('first_emi_date'))->toDateString();

                // for debugging
                if(!in_array(date('d', strtotime($emiDate)), [5, 18, 7, 07, 05])){
                    $userRo = User::where('id', 27)->first(['slack_id']); //sunil
                    $slack_id = isset($userRo->slack_id) && $userRo->slack_id ? [$userRo->slack_id] : [];
                    (new Slack(new Request(['title' => 'EMI Date Issue', 'fields' => ['Application ID' => $id, 'Date' => $emiDate, 'Data' => json_encode($data), 'Initiated By' => Auth::check() ? Auth::user()->name : ''], 'tagging' => $slack_id])))->send();
                    $data = ['status' => 'FAIL', 'message' => 'Failed to generated EMI. error - '. $emiDate.' is wrong'];
                    return response()->json($data, 200);
                }


                $application = new ApplicationEMICalculation();
                $application->application_id = $id;
                $application->status = 1;
                $application->emi_date = $emiDate;
                $application->fill($data);
                if ($consumerController->isProcessingFeeApplicable($id)) {
                    $application->processing_fee = 0;
                }
                $application->save();
                $irr_data = $accounting->getIrrRate($id, $data);
                if($irr_data){
                    $irr_data = json_decode($irr_data);
                    $application->rate = isset($irr_data->rate) ? $irr_data->rate : 0;
                    $application->annualised_interest = isset($irr_data->annualised_interest) ? $irr_data->annualised_interest : 0;
                    $application->irr_rate = isset($irr_data->irr_rate) ? $irr_data->irr_rate : 0;
                    $application->annualised_irr = isset($irr_data->annualised_irr) ? $irr_data->annualised_irr : 0;
                    $application->payment_frequency = $payment_frequency;
                    $application->save();
                }
                if(isset($data['flag'])){
                    $conApp = ConsumerApplication::where('id',$application->application_id)->first(['offer_id','approved_amount','state']);
                    if(($conApp->state == 'approved') || ($conApp->state == 'disbursement checklist done') || ($conApp->state == 'ready for disbursement')){
                        event(new EventPostCreateCustomer($application->application_id,'createCamReportCommand'));
                    }
                }
            }

            if(isset($data['remaining_emi']) && $data['remaining_emi']){
                $last_emi_date = Carbon::now()->addMonths($data['remaining_emi'])->toDateString();
                (new ConsumerApplicationController())->saveLastEMIDate($id, $last_emi_date);
            }

            //(new Jobs())->emiDueReminder($this->generateDues($id));

            if(($application->remaining_emi > $application->tenure || $application->emi == 0) && $this->is_calculated_once == 0){
                $this->is_calculated_once = 1;
                $this->generateEMI($request, $id);
            }

            $this->generateEMIPayments($id);

            (new MultiStageDisbursement())->generateDisbursementOffers($id);

            $repaymentController = new RepaymentController();
            $rps_exist = $repaymentController->checkRPSExists($id);
            if($application_status->activeOffer && $application_status->activeOffer->subvention_type_id > 1 && $application_status->lender_id != AvanseServices::$lender_id) {
                $_response = $repaymentController->getRPSDetails($id, true);
                if($_response && isset($_response[1]['emi_amount'])){
                    $application->emi = $_response[1]['emi_amount'];
                    $application->save();
                }elseif($rps_exist){
                    $repaymentController->deleteRPSRecord($id);
                }
            }elseif ($rps_exist){
                $repaymentController->deleteRPSRecord($id);
            }

            $data = ['status' => 'OK', 'message' => 'EMI Generated successfully'];
        } catch (\Exception $e) {
            $cwFactory = new CloudWatchLoggerFactory();
            $_data = array(
                'exception' => 'Exception occurred while generating EMI',
                'message' => $e->getMessage(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString()
            );
            $cwFactory->logger(json_encode($_data));
            $data = ['status' => 'FAIL', 'message' => 'Exception occurred while generating EMI'];
        }

        return response()->json($data, 200);
    }

    public function generateEMIPayments($id){
        try {
            $paymentTransaction = PaymentTransaction::where('application_id', $id)->whereIn('status', ['rejected', 'success', 'partial'])->first(['id']);
            $emiPayments = EmiPayment::where('application_id', $id)->whereIn('payment_status', ['success', 'partial'])->first(['id']);
            if (!isset($paymentTransaction->id) || !isset($emiPayments->id)) {
                $emiCalculation = ApplicationEMICalculation::where('application_id', $id)->first(['emi','emi_date']);
                $emiPayment = EmiPayment::where('application_id', $id)->first(['emi_amount','emi_date']);
                if (isset($emiCalculation->emi) && isset($emiPayment->emi_amount) && (($emiCalculation->emi != $emiPayment->emi_amount) || date('Y-m-d', strtotime($emiCalculation->emi_date)) != date('Y-m-d', strtotime($emiPayment->emi_date)))) {
                    EmiPayment::where('application_id', $id)->delete();
                }
            }
        }catch (\Exception $e){

        }
    }

    public function lockThePreviousEMICalculation($data, $approved_amount){
        unset($data['id']);

        if($this->ifThereIsChangeInEMI($data['application_id'], $data)) {

            $applicationLock = new ApplicationEMICalculationLock();
            $applicationLock->fill($data);
            $applicationLock->created_at = Carbon::now()->toDateTimeString();
            $applicationLock->re_scheduled_type = 0;
            $applicationLock->re_scheduled_by = Auth::user() ? Auth::user()->id : $data['user_id'];
            $applicationLock->approved_amount = $approved_amount;
            $applicationLock->save();
        }
    }

    public function ifThereIsChangeInEMI($application_id, $data){
        $applicationEMICalculationLock = ApplicationEMICalculationLock::where('application_id', $application_id)->orderBy('created_at', 'desc')->limit(1)->first(['id']);
        if (!isset($applicationEMICalculationLock->id)){
            return true;
        }
        $applicationEMICalculationLockUpdate = ApplicationEMICalculationLock::find($applicationEMICalculationLock->id);

        $applicationEMICalculationLockUpdateArray = $applicationEMICalculationLockUpdate->toArray();

        unset($data['id'], $data['created_at'], $data['updated_at'], $data['re_schedule_by'], $data['re_scheduled_type']);
        unset($applicationEMICalculationLockUpdateArray['id'], $applicationEMICalculationLockUpdateArray['created_at'], $applicationEMICalculationLockUpdateArray['updated_at'], $applicationEMICalculationLockUpdateArray['re_schedule_by'], $applicationEMICalculationLockUpdateArray['re_scheduled_type']);

        if(Carbon::parse($data['emi_date'])->toDateString() != Carbon::parse($applicationEMICalculationLockUpdateArray['emi_date'])->toDateString() || $data['offer_id'] != $applicationEMICalculationLockUpdateArray['offer_id']){
            $cwFactory = new CloudWatchLoggerFactory();
            $_data = array(
                'exception' => 'EMI generating - Lock Update',
                'message' => ['emi_date' => $data['emi_date'], 'lock_emi_date' => $applicationEMICalculationLockUpdateArray['emi_date']],
                'line' => ['offer_id' => $data['offer_id'], 'lock_offer_id' => $applicationEMICalculationLockUpdateArray['offer_id']]
            );
            $cwFactory->logger(json_encode($_data));
            return true;
        }
        return false;
    }

    /**
     * @param $id
     * @param bool $is_break
     * @param bool $is_generate
     * @return array
     */
    public function generateDues($id, $is_break = false, $is_generate = true){
        $i = 0;
        $user = ConsumerApplication::with('emi')->where('id',$id)->first();
        $emiCalculation = new EMICalculation($this->request);
        $dues = $emiCalculation->getRepaymentSchedule($user, $is_generate);
        $payload = [];
        if(isset($dues->emis)) {
            foreach ($dues->emis as $index => $emi_amount) {
                $emi_date = date('Y-m-d', strtotime($user->emi->emi_date . ' +' . $i . ' month'));
                $available_at = Carbon::createFromFormat('Y-m-d', $emi_date)->subDay(2);
                $payment_emi = new PaymentEmi();
                $holidays = [];//$payment_emi->getHolidayList();
                while(in_array($available_at,$holidays) || $available_at->isSunday()){
                    $available_at = Carbon::createFromFormat('Y-m-d', $available_at->toDateString())->addDay(1);
                }
//                if ($available_at->isSunday()) {
//                    $available_at = $available_at->subDay(2);
//                }
//                if ($available_at->isSaturday()) {
//                    $available_at = $available_at->subDay(1);
//                }

                $is_process = true;
                if(!$is_break){
                    if(strtotime($available_at->toDateString()) < strtotime('now')){
                        $is_process = false;
                    }
                }

                if($is_process) {
                    $payload[] = [
                        'payload' => json_encode(['id' => $id, 'offer_id' => $user->emi->offer_id, 'emi_id' => $user->emi->id, 'emi_date' => $emi_date, 'amount' => $emi_amount]),
                        'from' => 'emiDueReminder',
                        'application_id' => $id,
                        'available_at' => ($is_break) ? $emi_date : $available_at->toDateString() . ' 10:00:00',
                        'created_at' => Carbon::now()->toDateTimeString()
                    ];
                }

                if ($is_break) {
                    if ($is_break == $available_at->toDateString()) {
                        //$payload[] = (count($payload) > 0) ? $payload[count($payload) - 1] : [];
                        break;
                    }
                }

                $i++;
            }
        }

        return ['payload'=>$payload,'id'=>$id];
    }

    public function getEMIDateByPaymentFrequency($user, $i){
        if (!$i){
            return date('Y-m-d', strtotime($user->emi->emi_date));
        }
        switch ($user->emi->payment_frequency){
            case 1:
                return date('Y-m-d', strtotime($user->emi->emi_date . ' +' . $i . ' month'));
                break;
            case 2:
                if (date('d', strtotime($user->emi->emi_date)) == 5){
                    $month = ($i % 2 == 0) ? (($i) ? $i / 2 : 0) : ($i ? ($i - 1) / 2 : 0);
                    $date = ($i % 2 == 0) ? '05' : '18';
                }else{
                    $month = ($i % 2 == 1) ? (($i) ? round($i / 2) : 0) : ($i ? round(($i - 1) / 2) : 0);
                    $date = ($i % 2 == 0) ? '18' : '05';
                }
                return date('Y-m', Carbon::parse($user->emi->emi_date)->addMonth($month)->timestamp).'-'.$date;
                break;
            case 3:
                return Carbon::parse($user->emi->emi_date)->addWeek($i)->startOfWeek()->addDays(2)->toDateString();
                break;
            case 4:
                return Carbon::parse($user->emi->emi_date)->addDay($i)->toDateString();
                break;
            default:
                return date('Y-m-d', strtotime($user->emi->emi_date . ' +' . $i . ' month'));
                break;
        }
    }

    /**
     * @param $id
     * @param bool $is_break
     * @param bool $is_generate
     * @return array
     */
    public function generateAdvanceDues($id, $is_break = false, $is_generate = true){
        $i = 0;
        $user = ConsumerApplication::with('emi')->where('id',$id)->first();
        $emiCalculation = new EMICalculation($this->request);
        $dues = $emiCalculation->getRepaymentSchedule($user, $is_generate);
        $payload = [];
        if(isset($dues->emis)) {
            foreach ($dues->emis as $index => $emi_amount) {
                $emi_date = $this->getEMIDateByPaymentFrequency($user, $i);
                $emi_date = Carbon::parse($emi_date);
                $payment_emi = new PaymentEmi();
                $holidays = [];//$payment_emi->getHolidayList();
                /*while(in_array($emi_date->toDateString(),$holidays) || $emi_date->isSunday()){
                    $emi_date = Carbon::createFromFormat('Y-m-d', $emi_date->toDateString())->addDay(1);
                }*/
                $available_at = Carbon::createFromFormat('Y-m-d', $emi_date->toDateString());

                $is_process = true;

                if(!$is_break){
                    if($available_at->timestamp < Carbon::now()->subDay(3)->startOfDay()->timestamp){
                        //$is_process = false;
                    }
                }

                if($is_process && !(BNPL::is($user->merchant_id)) && !in_array($user->merchant_id,[6418,6517,6598,6865,6600])) {
                    $payload[] = [
                        'payload' => json_encode(['id' => $id, 'offer_id' => $user->emi->offer_id, 'emi_id' => $user->emi->id, 'emi_date' => $emi_date->toDateString(), 'amount' => $emi_amount]),
                        'from' => 'emiDueReminder',
                        'application_id' => $id,
                        'available_at' => ($is_break) ? $emi_date->toDateString() : $available_at->toDateString() . ' 10:00:00',
                        'created_at' => Carbon::now()->toDateTimeString()
                    ];
                }

                if ($is_break) {
                    if ($is_break == $available_at->toDateString()) {
                        //$payload[] = (count($payload) > 0) ? $payload[count($payload) - 1] : [];
                        break;
                    }
                }

                $i++;
            }
        }

        $payload = $payload ? $this->simply($user, $payload) : $payload;

        return ['payload'=> $payload ,'id'=>$id];
    }

    public function simply($user, $response){

        $payload = [];
        foreach($response as $item){
            $payload[] = json_decode($item['payload'], 1);
        }

        $payloadData = (new LoanManagement())->applyMoratorium($user, $payload);

        $payload = [];
        foreach ($payloadData as $item){
            if(!isset($item['due_date'])){
                return $response;
                break;
            }
            $is_process = true;
            if(Carbon::createFromFormat('Y-m-d',$item['due_date'])->timestamp < Carbon::now()->subDay(3)->startOfDay()->timestamp) {
                $is_process = false;
            }

            if($is_process){
                $item['emi_date'] = $item['due_date'];
                $payload[] = [
                    'payload' => json_encode($item),
                    'from' => 'emiDueReminder',
                    'application_id' => $item['id'],
                    'available_at' => $item['due_date'] . ' 10:00:00',
                    'created_at' => Carbon::now()->toDateTimeString()
                ];
            }
        }

        return $payload;
    }

}
