<?php
/**
 * Created by PhpStorm.
 * User: sunil
 * Date: 9/29/18
 * Time: 4:53 PM
 */

namespace App;


use App\Avanse\Processes\AvanseProcesses;
use App\Avanse\Services\SubService\CreateFinance;
use App\Console\Commands\AdviserReminders;
use App\Console\Commands\BasicReminders;
use App\Console\Commands\EveryFiveMinutes;
use App\Console\Commands\PaymentCron;
use App\Console\Commands\SubventionProcessingInvoice;
use App\Console\Commands\TallyBridge;
use App\Events\V1\EventJobs;
use App\Exports\Exporter;
use App\Http\Controllers\Admin\AccountingController;
use App\Http\Controllers\Admin\CampaignController;
use App\Http\Controllers\Admin\ConsumerApplicationController;
use App\Http\Controllers\Admin\ConsumerDocument;
use App\Http\Controllers\Admin\DisbursementController;
use App\Http\Controllers\Admin\FLDGController;
use App\Http\Controllers\Admin\LenderServices;
use App\Http\Controllers\Admin\MerchantController;
use App\Http\Controllers\Admin\TallySettlementController;
use App\Http\Controllers\ApiController;
use App\Http\Controllers\Couriers\CouriersController;
use App\Http\Controllers\FrontController;
use App\Http\Controllers\MConnector\MerchantApiIntegration;
use App\Http\Controllers\MerchantApiController;
use App\Http\Controllers\NachController;
use App\Http\Controllers\TestingController;
use App\Http\Controllers\EMICheckout\EMICheckoutController;
use App\Imports\CollectionImport;
use App\LoanHypothecation\LoanHypothecation;
use App\Logging\CloudWatchLoggerFactory;
use App\Tally\Tally;
use App\Tally\TallyConnector;
use App\Http\Controllers\Admin\CollectionController;
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Facades\Excel;
use App\KarzaVideo;
use Hashids\Hashids;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Admin\AutoDCDController;


class Jobs
{
    private $applications;
    private $applicationsJobData;
    private $status_array = ['disbursed','nach registered'];
    public $emailCount = 0;
    public $smsCount = 0;
    private $event;

    public function __construct(){

    }

    public function insertQueue($payload){

        $job = new JobProvider();
        $job->insert($payload);
    }

    public function start($event = array()){
        $this->event = $event;
        $jobs = JobProvider::with('application')->where('is_available',0)->where('available_at','<=',Carbon::now()->toDateTimeString());
        if(isset($this->event->from)){
            $jobs = $jobs->where('from', $this->event->from);
        }else if(isset($this->event->job_id) && $this->event->job_id > 0){
            $jobs = $jobs->where('id', $this->event->job_id);
        }
        $jobs = $jobs->limit(5)->get();

        $disableIds = [];
        $_id = [];
        $_plData = [];
        $stop_exec = [];
        foreach($jobs as $key => $job){
            if($job->from == 'paytmPayments' || $job->from == 'razorpayPayments') {
                if(!in_array($job->application_id, $_id) || !in_array($job->payload, $_plData)){
                    $_id[] = $job->application_id;
                    $_plData[] = $job->payload;
                    $disableIds[] = $job->id;
                }else{
                    $stop_exec[] = $job->id;
                    unset($jobs[$key]);
                }
            }else{
                $disableIds[] = $job->id;
            }
        }

        if($_id != [] && $_plData != []){
            JobProvider::whereNotIn('id', $disableIds)->where(function ($query) use ($stop_exec, $_plData) {
                $query->whereIn('id', $stop_exec)->orWhereIn('payload', $_plData);
            })->update(['is_available' => 2]);

        }

        JobProvider::whereIn('id',$disableIds)->update(['is_available' => 1]);

        if ($jobs->count()) {
            $reminder = new ConsumerApplicationController();
            foreach ($jobs as $job) {
                try {
//                     $jobID = JobDashboard::log([
//                         'job' => $job,
//                         'status' => 'Started'
//                     ]);
//                    $this->event->comment($job->id);
                    $this->applications[] = $job->application_id;
                    //$this->event->comment('Application_id: '.$job->application_id);

                    $payload = json_decode($job->payload);
                    //$this->event->comment('Payload: '.$payload);

                    $this->applicationsJobData[$job->application_id] = $payload;
                    $this->queue($job, $reminder, $payload);
                }catch (\Exception $e){
                    /*if ($id) {
                        JobProvider::whereIn('id', $id)->delete();
                    }*/
                    // if(isset($jobID) && $jobID) {
                        // JobDashboard::log([
                        //     'job' => $job,
                        //     'status' => 'Failed',
                        //     'response' => $e->getMessage() . '|' . $e->getLine() . '|' . $e->getFile()
                        // ], $jobID);
                    $cwFactory = new CloudWatchLoggerFactory();
                    $cwFactory->logger(json_encode(['title' => 'Job Error', 'error' => $e->getMessage(), 'line' => $e->getLine(), 'file' => $e->getFile(), 'trace' => $e->getTraceAsString(), 'application_id' => $job->application_id]));
//                    (new Slack(new Request(['title' => 'Job Error', 'fields' => ['error' => $e->getMessage(), 'line' => $e->getLine(), 'file' => $e->getFile(), 'trace' => $e->getTraceAsString(), 'application_id' => $job->application_id, 'id_type' => 'application_id']])))->send();
                    //$this->sendOps($e->getTraceAsString(), [$e->getFile(),$e->getLine(), $id]);
//                    (new Slack(new Request(['title' => 'Job Error', 'fields' => ['error' => $e->getMessage(), 'line' => $e->getLine(), 'file' => $e->getFile(), 'trace' => $e->getTraceAsString(), 'job_id' => $job->id, 'application_id' => $job->application_id, 'id_type' => 'application_id']])))->send();
                }
            }

            /*$resetIds = array_values(array_diff($disableIds, $id));

            if($resetIds) {
                JobProvider::whereIn('id', $resetIds)->update(['is_available' => 0]);
                $this->event->comment('Applications not executed, will be re-executed in next phase: '.implode(', ',$resetIds));
            }*/

//            if ($id) {
//                JobProvider::whereIn('id', $id)->delete();
//            }
        }

        $this->anotherJobs();
        if(!$jobs->count())
            return false;
        /*if($this->applications){
            $request = new Request();
            $request->attributes->add(['applicationsJobData' => $this->applicationsJobData, 'applications' => $this->applications]);
            (new NachController($request))->sendMonthlyNach();
        }*/

        return true;
    }

    public function queue($job, ConsumerApplicationController $reminder, $payload, $jobID = 0){
        switch ($job->from) {
            case 'emiDueReminder':
                $data = $reminder->getTemplateReminders(5, $job->application_id, $payload);
                $data = $data->getData();
                if (isset($data->error)) {
                    $this->sendOps($data->error, $job);
                } else {
                    $this->sendEmail($data, $job);
                }
                break;
            case 'courierNach':
                $this->courierNach($job);
                break;
            case 'misReport':
                $this->misReport($job);
                break;
            case 'run_finbit_report_analysis':
                $is_failed = (new FinBit((new Request((array) $payload))))->run_after_upload_analysis();
                if ($is_failed){
                    $available_at = Carbon::now()->addMinutes(5)->toDateTimeString();
                    $this->updateJob($job->id, $available_at);
                }
                break;
            case 'statusChange':
                $this->statusChange($job, $payload);
                break;
            case 'refund_initiate':
                (new DisbursementController((new Request((array) $payload))))->runRefundFromCashfree();
                break;
            case 'refund_initiate_status':
                (new DisbursementController((new Request((array) $payload))))->checkTransferStatus($payload->application_id, $payload->id);
                break;
            case 'merchant_analysis':
                $this->merchantAnalysis();
                break;
            case 'non_stater_list':
                (new AdviserReminders())->getNonStaterList();
                break;
            case 'pending_collection_report':
                (new AccountingController())->getMerchantCollectionReport();
                break;
            case 'tally':
                (new TallyJobsListener())->start();
                break;
            case 'fldg_update':
                $this->fldgUpdate($payload);
                break;
            case 'applicationReminder':
                $this->sendWaitReminder($job, $payload);
                break;
            case 'applicationEscalation':
                $this->applicationEscalationReminder($job, $payload);
                break;
            case 'SubventionProcessingInvoice':
                (new SubventionProcessingInvoice())->handle($payload->invoice_type);
                break;
            case 'sendMerchantTarget':
                (new BasicReminders())->sendMerchantTarget();
                break;
            case 'basic_communication':
                $this->basicCommunication($job, $payload);
                break;
            case 'initiateUTRStatusAvanse':
                $this->initiateUTRStatusAvanse($job, $payload);
                break;
            case 'validateEmails':
                $this->validateEmails();
                break;
            case 'mConnectWebhook':
                (new MerchantApiIntegration(new Request((array) $payload)))->push();
                break;
            case 'merchantDataFormat':
                (new TestingController())->merchantDataFormat($this->event);
                break;
            case 'incomplete_form_communication':
                (new TestingController())->incompleteFormCommunication($job);
                break;
            case 'auto_abort_incomplete_form':
                (new TestingController())->incompleteFormAbort();
                break;
            case 'overDuePaymentReminder':
                $all_due_cases = 1;
                $start_time = time();
                $loan_management = new LoanManagement();
                $application_ids = explode(',', $payload->id);
                if (_env('OVERDUE_REMINDER_MAILS') == 'OLD') {
                    foreach($application_ids as $application_id){
                        $response = $loan_management->overDueReminder($application_id, 1, 1, 0, $all_due_cases, $this->event);
                    }

                    $total_email_sent = $loan_management->emailCount ?? 0;
                    $total_sms_sent = $loan_management->smsCount ?? 0;

                    if ($total_sms_sent || $total_email_sent) {
                        (new Slack(new Request(['title' => 'Over Due Reminder Summary', 'fields' => ['Total Email Sent' => $total_email_sent, 'Total SMS Sent' => $total_sms_sent], 'group' => 'payment_collection'])))->send();
                    }else{
                        (new Slack(new Request(['title' => 'Over Due Reminder Summary', 'fields' => ['Total Email Sent' => 0], 'group' => 'payment_collection'])))->send();
                    }

                    $cwFactory = new CloudWatchLoggerFactory();                        
                    $service_count = (isset($response['service_count'])) ? $response['service_count'] : 0;
                    
                    $_data = [
                        'process' => 'Overdue Reminder OLD - FINAL SUMMARY',
                        'status' => 'COMPLETED',
                        'service_count_successful' => $service_count,
                        'total_email_sent' => $total_email_sent,
                        'total_sms_sent' => $total_sms_sent,
                        'start_time' => $start_time,
                        'end_time' => time(),
                        'full_response_summary' => $response, 
                    ];
                    
                    $cwFactory->logger(json_encode($_data));
                }
                else{
                    $collectionEmail = $payload->collectionEmail ?? null;
                    if (empty($collectionEmail)){
                            $collectionEmail=_env('COLLECTION_MAIL');
                    }
                    $response = $loan_management->overDueReminderPython($application_ids, $collectionEmail);
                    $cwFactory = new CloudWatchLoggerFactory();
                                            
                    // Prepare structured log data
                    $_data = [
                        'process' => 'Over Due Reminder DIRECT',
                        'status' => true,
                        'start_time' => $start_time,
                        'collectionEmail' => $collectionEmail,
                        'end_time' => time(),
                        'response_summary' => [
                            'message' => $response['message'] ?? 'Process completed.',
                            'full_response' => $response
                        ]
                    ];  
                    $cwFactory->logger(json_encode($_data));                
                }
                break;
            case 'app_reminder':
                (new ApiController())->appReminder($job, $payload);
                break;
            case 'setPreApprovedAndDoc':
                (new TestingController())->setPreApprovedAndDoc();
                break;
            case 'getAnalyticsData':
                (new TestingController())->getAnalyticsData($this->event);
                break;
            case 'avanseNewLoanApplication':
                (new CreateFinance(new Request()))->sendNotificationToAvanse($payload);
                break;
            case 'getDataForML':
                (new TestingController())->getDataForML($this->event);
                break;
            case 'sendRewardsReminder':
                (new BasicReminders())->sendRewardsReminder();
                break;
            case 'TallyEntryForOLDApplication':
                (new TestingController())->TallyEntryForOLDApplication();
                break;
            case 'sendAccountStatement':
                (new BasicReminders())->sendAccountStatement($this->event);
                break;
            case 'invoicesFixes':
                (new TestingController())->invoicesFixes($this->event);
                break;
            case 'camGenerate':
                (new ConsumerApplicationController())->generateCAMReport($job->application_id);
                break;
            case 'metadataUpdate':
                (new NachController())->updateMetadata($payload->id, $payload->fin_refence_id);
                break;
            case 'partial_disbursement':
                (new MultiStageDisbursement())->sendPartialDisbursementNotification($job, $payload);
                break;
            case 'schedule_verification_call':
                $this->scheduleVerificationCall($job, $payload);
                break;
            case 'getCIBILPaymentReport':

                //Update Amount over due before preparing bureau file
                //(new PaymentCron())->handle(); do not uncomment
                //End


                $current = Carbon::parse($job->available_at);
                $payload = (array) $payload;
                (new ConsumerApplicationController())->getCIBILPaymentReportV1(new Request((array) $payload));
                $date = $current->format('d');
                if($date == 15){
                    $newDate = $current->copy()->endOfMonth()->setTime(
                        $current->hour,
                        $current->minute,
                        $current->second
                    )->toDateTimeString();
                    $from_date = $current->copy()->addDay()->startOfDay()->toDateString();
                    $to_date = $current->copy()->endOfMonth()->startOfDay()->toDateString();
                }else{
                    $newDate = $current->copy()->addMonthsNoOverflow(1)->day(15)->toDateTimeString();
                    $from_date = $current->copy()->addDay()->startOfDay()->toDateString();
                    $to_date = $current->copy()->addMonthsNoOverflow(1)->day(15)->startOfDay()->toDateString();
                }
                $newPayload = $payload;
                $newPayload['from_date'] = $from_date;
                $newPayload['to_date'] = $to_date;

                JobProvider::where('id', $job->id)->update(['is_available' => 0,'available_at' => $newDate, 'payload' => json_encode($newPayload)]);
                break;
            case 'bounce_invoices_creation':
                (new LoanManagement())->creationBouncePenal($payload);
                break;
            case 'updateApplicationIdDetails':
                (new TestingController())->updateApplicationIdDetails($this->event);
                break;
            case 'fetchDigioCustomerPhotoManually':
                (new ApiController())->fetchDigioCustomerPhotoManually(new Request((array) $payload));
                break;
            case 'uploadPendingLotusPayEntries':
                (new TestingController())->uploadPendingLotusPayEntries();
            case 'PTPDate':
                (new ConsumerApplicationController())->PTPDateNotification();
                break;
            case 'InvokeCommunicationPayout':
                (new ConsumerApplicationController())->invokeCommunication($job->application_id, false, $payload);
                break;
            case 'gst_filing':
                (new AccountingController())->exportGSTFiling(new Request((array) $payload));
                break;
            case 'create_mandate_document':
                $mandateModel = Mandate::where('id', $payload->id)->first();
                (new NachController())->generateMandateDocument($mandateModel->consumer_application_id, $mandateModel);
                break;
            case 'updateAppDataInfo':
                (new ConsumerApplicationController())->updateAppDataInfo(new Request((array) $payload));
                break;
            case 'initiateForLatestBankStatement':
                (new ConsumerApplicationController())->initiateForLatestBankStatementToSlack($job->application_id);
            case 'documentUploadBot':
                (new ConsumerApplicationController())->documentUploadBot(new Request((array) $payload));
                break;
            case 'runThroughCron':
                (new ConsumerDocument(new Request((array) $payload)))->downloadDocument($job->application_id);
                break;
            case 'paytm_processing_fee_process':
                (new LoanManagement())->paymentReconcile((array) $payload);
                break;
            case 'initiate_for_legality_loan_hypothetical':
                $this->initiateForLegalityLoanHypothetical((array) $payload);
                break;
            case 'uploadCompanyData':
                (new TestingController())->uploadCompanyData();
                break;
            case 'getMISReport':
                (new MerchantController())->getMISReport($payload->merchant_id, new Request((array) $payload));
                break;
//            case 'downloadMISReport':
//                (new MerchantController())->downloadMISReport(new Request((array) $payload));
                break;
            case 'generateEsignLoanAgreement':
                (new TestingController())->generateEsignLoanAgreement($job->application_id);
                break;
            case 'esign_customer_update':
                $system = isset($payload->system) ? 1 : 0;
                (new FrontController())->sendEsignToCustomer($job->application_id, $system);
                break;
            case 'first_installment_mandate_date_mismatch':
                (new ConsumerApplicationController())->sendInstallmentDateMismatch(new Request((array) $payload));
                break;
            case 'uploadExGratia':
                (new TestingController())->uploadExGratia();
                break;
            case 'export_auto_decision_data':
                (new TestingController())->exportAutoDecisionRulesData($payload->iteration);
                break;
            case 'sendConstantMessage':
                $lenderService = new LenderServices(new Request());
                $lenderService->sendConstantMessage($job->application_id);
                break;
            case 'karzaTestingSSL':
                (new KarzaAPI())->karzaTesting();
                break;
            case 'generate_subv_inv':
                (new AccountingController())->getMonthlySubvention();
                break;
            case 'reviseDocsViaMconnect':
            case 'reviseDocuments':
                (new ConsumerApplicationController())->reviseDocuments(new Request((array) $payload));
                break;
            case 'digioKYCSlack':
                (new ApiController())->digioKYCSlack($job, $payload);
                break;
            case 'karzaPurge':
                (new KarzaVideo(new Request()))->karzaPurge($job, $payload);
                break;
            case 'emiCheckoutGenerateDocuments':
                (new EMICheckoutController())->generateDocuments(new Request((array) $payload));
                break;
            case 'vkycDropOff':
                (new ApiController())->vkycDropOff($job, $payload);
                break;
            case 'preEligibilityConsent':
                (new LenderServices(new Request()))->preEligibilityConsentDocument($job->pre_eligibility_application_id);
                break;
            case 'mconnectConsent':
                $lenderService = new LenderServices(new Request());
                $hashids = new Hashids('Creditfair by CS', 20);
                $hashed_id = $hashids->encode($job->application_id);
                $status = isset($payload->status) ? $payload->status : 'agree';
                $source = isset($payload->source) ? $payload->source : 'mconnect';
                $lenderService->addConsentDocument($hashed_id, $payload->applicant_type, $status, $source);
                break;
            case 'paytmPayments':
                (new ApiController())->paytmpaymentupdate((array)$payload);
               break;
            case 'razorpayPayments':
                (new ApiController())->paytmpaymentupdate((array)$payload, 'Razorpay');
                break;
            case 'sendCampaignPreApproval':
                (new FrontController())->sendCampaign();
                break;
            case 'settlement_ptp_progress':
                (new AccountingController())->settlementPtpProgress($job, $payload);
                break;
            case 'create_monitoring_request':
                $accountAggregator = new AccountAggregator(new Request((array) $payload));
                $accountAggregator->processMonitoringRequest();
                break;
            case 'autoDCD':
                (new AutoDCDController())->process($job, $payload);
                break;
            case 'run_ebill_ocr_workflow':
                $id = $payload->id;
                $file_path = $payload->file_path;
                $rehit = isset($payload->rehit) ? $payload->rehit : false;
                (new ApiController())->triggerEbillOcr($id, $file_path, $rehit);
                break;

        }

        // if($jobID) {
            // JobDashboard::log([
            //     'job' => $job,
            //     'ended_at' => Carbon::now()->toDateTimeString(),
            //     'status' => 'Completed'
            // ], $jobID);
        // }
    }

    public function initiateUTRStatusAvanse($job, $payload){
        try {
            $getDisbursementInstructions = (new AvanseProcesses(new Request((array)$payload)))->getDisbursementInstructions();
            if (!is_array($getDisbursementInstructions) && is_int($getDisbursementInstructions)) {
                $application = ConsumerApplication::where('id', $payload->id)->first(['id','name']);
                (new Slack(new Request(['title' => 'UTR Status (Disbursement) Success', 'fields' => ['Name' => $application->name, 'CF Disbursement ID' => $getDisbursementInstructions, 'App ID' => $payload->id], 'group' => Slack::$AVANSE_DISBURSEMENT])))->send();

                $avanseMandate = AvanseMandate::where('application_id', $payload->id)->first(['id']);
                if (!isset($avanseMandate->id)) {
                    $mandateApproval = (new AvanseProcesses(new Request((array)$payload)))->mandateApproval();
                    if (is_array($mandateApproval) || !is_int($mandateApproval)) {
                        (new Slack(new Request(['title' => 'Mandate Approval Failed (Update Through Admin)', 'fields' => ['Name' => $application->name, 'message' => json_encode($mandateApproval), 'App ID' => $payload->id], 'group' => Slack::$AVANSE_DISBURSEMENT])))->send();
                    }
                }

            } else {
                JobProvider::where('id', $job->id)->update(['is_available' => 0, 'available_at' => Carbon::now()->addHour(1)->toDateTimeString()]);
                (new Slack(new Request(['title' => 'UTR Status (Disbursement) Pending', 'fields' => ['message' => json_encode($getDisbursementInstructions)], 'group' => Slack::$AVANSE_DISBURSEMENT])))->send();
            }
        }catch (\Exception $e){
            (new Slack(new Request(['title' => 'UTR Status (Disbursement) Exception', 'fields' => ['Job Id' => $job->id, 'Application ID' => $job->application_id, 'Message' => $e->getMessage(), 'L' => $e->getLine(), 'F' => $e->getFile(), 'T' => $e->getTraceAsString()], 'group' => Slack::$AVANSE_DISBURSEMENT])))->send();
            JobProvider::where('id',$job->id)->update(['is_available' => 0, 'available_at' => Carbon::now()->addHour(1)->toDateTimeString()]);
        }
    }

    public function fldgUpdate($payload){
        (new FLDGController(new Request()))->getAvailableExposure($payload->merchant_id, $payload->id, true);
    }

    public function scheduleVerificationCall($job, $payload){
        $application_id = $job->application_id;
        $consumerApplication = ConsumerApplication::with('advisor','calls')->where('id', $application_id)->first(['id','name','created_by','state']);

        (new ConsumerApplicationController())->fetchCallDetails($consumerApplication, new Request());

        $CallLogs = CallLogs::where('_id', $application_id)->where('id_type','application_id')->where('status','completed')->where('purpose', 'verification_call')->first(['id']);

        if ($consumerApplication->advisor && $consumerApplication->advisor->mobile_number && $consumerApplication->state == 'approved' && !isset($CallLogs->id)) {
            $application_link = asset("admin/consumer-applications/edit/" . $application_id);
            try {
                $application_link = Shortio::getUrl($application_link);
            } catch (\Exception $e) {
            }

            $message = "Hi ".$consumerApplication->advisor->name.", \nPlease complete verification call of " . $consumerApplication->name . "\n" . $application_link;
            sendWhatsAppMessage($consumerApplication->advisor->mobile_number, $message);
        }

        return true;
    }

    public function fetchExotelData(){
        $call_logs = CallLogs::with('consumer','merchant','center','users')->whereNull('status')->orWhere('status', 'in-progress')->get();
        return $call_logs;
    }

    public function updateJob($job_id, $available_at){
        JobProvider::where('id',$job_id)->update(['is_available' => 0, 'available_at' => $available_at]);
    }

    public function basicCommunication($job, $payload){
        if (isset($payload->type)){
            switch ($payload->type){
                case 'referral_communication':
                    $function = $payload->type;
                    return $this->$function($job, $payload);
                    break;
                default:
                    break;
            }
        }
    }

    public function referral_communication($job, $payload){
        $application = ConsumerApplication::where('id',$job->application_id)->first(['merchant_id']);
        if (isset($application->merchant_id)) {
            $merchant = Merchant::find($application->merchant_id);
            $user = User::find($payload->user_id);
            (new MerchantApiController())->sendCommunicationToRefer([$user, $merchant], 3);
        }
    }

    public function courierNach($job){
        if(isset($job->application_id)){
            (new CouriersController(new Request()))->NACHStatus($job->application_id, true);
            JobProvider::where('id',$job->id)->update(['available_at' => Carbon::tomorrow()->toDateString().' 10:00:00','is_available' => 0]);
        }

    }

    public function misReport($job){
        $payments = PaymentTransaction::with('application.proFormaInvoice','application.merchant')->where('payment_date','>=',Carbon::now()->subDay(1)->startOfDay()->toDateTimeString())->where('payment_date','<=',Carbon::now()->subDay(1)->endOfDay()->toDateTimeString())->whereNull('is_deleted_at')->get();

        if($payments) {
            $data[] = ['ID','Agreement Number', 'Name', 'Merchant Name','Phone', 'Paid Amount', 'Payment Date', 'Payment Mode', 'Transaction ID'];
            foreach ($payments as $payment) {
                $data[] = [
                    'id' => $payment->application_id,
                    'agreement_number' => isset($payment->application->proFormaInvoice->loan_application_no) ? $payment->application->proFormaInvoice->loan_application_no : '',
                    'name' => $payment->application->name,
                    'merchant_name' => $payment->application->merchant->merchant_name,
                    'phone' => $payment->application->mobile_number,
                    'paid_amount' => $payment->amount,
                    'date' => $payment->payment_date,
                    'payment_mode' => $payment->mode,
                    'transaction_id' => $payment->trasanction_id
                ];
            }

            $file = time().'_'.Carbon::now()->toDateTimeString().'_MIS_Report.xlsx';
            $mailData['email'] = $emails = !env('APP_CONNECTION') ? ['pratik@creditfair.in', 'sunil@creditfair.in', 'dinesh@creditfair.in'] : ['imran@creditfair.in','ketan@creditfair.in','rajendra@creditfair.in','surbhi@creditfair.in','skjha@kmglobal.in','arpita@kmglobal.in'];


            $requestData = new Request(['data' => $data, 'sheet' => 'MIS Report']);
            Excel::store((new Exporter($requestData)), $file);


            Mail::send('emails.reminders.basic_reminder', [
                'body' => 'MIS Report Dated '.Carbon::now()->subDay(1)->toDateString(),
            ], function ($message) use ($mailData, $file) {
                $message->to($mailData['email'])->subject('Daily Payment MIS');
                $message->attachData(file_get_contents(storage_path().'/app/'.$file), 'MIS Report Dated '.Carbon::now()->toDateTimeString().'.xlsx');
            });

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

            JobProvider::where('id', $job->id)->update(['available_at' => Carbon::tomorrow()->toDateString() . ' 11:00:00', 'is_available' => 0]);
        }
    }

    public function initiateForLegalityLoanHypothetical($data){
        $id = $data['id'];
        $apiController = new ApiController();
        $request = new Request();
        $request->merge(['id' => $id]);
        $isHypothecationActive = $apiController->canHypothecated($id);
        if ($isHypothecationActive) {
            $loanHypothecationModel = LoanHypothecationModel::where('application_id', $id)->whereNull('deleted_at')->orderBy('created_at', 'desc')->first();
            if (!isset($loanHypothecationModel->id)){
                $apiController->initiateHypothecation($request);
            }
        }

        $hypothecation = new LoanHypothecation($request);
        $flag = $hypothecation->triggerHypothecationCommunication($id);
        if($flag === 1) {
            (new Slack(new Request(['title' => 'Hypothecation Agreement Not Fetched ', 'fields' => ['application_id' => $id], 'group' => Slack::$STAGE_TESTING])))->send();
        }else if($flag === 2){
            (new Slack(new Request(['title' => 'Hypothecation Agreement Already Signed ', 'fields' => ['application_id' => $id], 'group' => Slack::$STAGE_TESTING])))->send();
        }else if($flag === 3){
            (new Slack(new Request(['title' => 'Hypothecation Agreement Email Trigger Issue ', 'fields' => ['application_id' => $id], 'group' => Slack::$STAGE_TESTING])))->send();
        }else {
            (new Slack(new Request(['title' => 'Hypothecation Agreement Sent ', 'fields' => ['application_id' => $id], 'group' => Slack::$STAGE_TESTING])))->send();
        }
    }

    public function statusChange($job, $payload){
        request()->merge((array)$payload);
        return (new ConsumerApplicationController())->updateStatusFromJob($job->application_id);
    }
    public function validateEmails(){
        $emails = UserEmails::get(['email'])->toArray();
        $data = ConsumerApplication::whereNotIn('email',array_map(function ($item){return $item['email'];},$emails))->whereNull('is_deleted')->get(['email','id']);

        foreach ($data as  $item){
            UserEmails::validates(['emails' => [$item->email],'type' => 'application_id', 'id' => $item->id]);
        }
        echo 'done';
    }


    public function merchantAnalysis(){
        return (new TestingController())->getMerchantWiseCustomerAppData(new Request());
    }

    public function emiDueReminder($payload){
        $emiDueReminder = JobProvider::where('application_id',$payload['id'])->where('from','emiDueReminder')->first(['id']);
        if (isset($emiDueReminder->id)) {
            JobProvider::where('id',$emiDueReminder->id)->delete();
        }
        $this->insertQueue($payload['payload']);
    }


    public function applicationEscalationReminder($job, $payload){

        try {
            $application = ConsumerApplication::with('merchant', 'application_element.merchant_center')->where('id', $job->application_id)->first();
            if($application->state == 'waiting for documents' || $application->state == 'in-process') {
                $applicationObject = new ConsumerApplicationController();

                if ($payload->action == 'aborted' && (isset($application->merchant) && $application->merchant->is_auto_abort == 1)) {
                    ConsumerApplication::where('id', $job->application_id)
                        ->update(['state' => $payload->action]);

                    StatusLogs::insert([
                        'application_id' => $job->application_id,
                        'user_id' => 107,
                        'status' => $payload->action,
                        'created_at' => Carbon::now()->toDateTimeString()
                    ]);

                    $applicationObject->sendMessageToMerchant($payload->action, $job->application_id);
                } else if ($application->state == 'waiting for documents') {
                    $cc_emails = [];
                    if (isset($application->mobile_number) && !empty($application->mobile_number)) {

                        $templateId = isset($payload->templateId) ? $payload->templateId : '';
                        $args = isset($payload->args) ? $payload->args : '';
                        $templateDetails = isset($payload->templateDetails) ? $payload->templateDetails : '';

                        send_sms($application->mobile_number, ['message'=>$payload->sms,'id'=>$job->application_id,'id_type'=>'application_id', 'templateId' => $templateId, 'args' => $args, 'templateDetails' => $templateDetails]);
                    }

                    if ($payload->action == 'final_reminder') {
                        if(isset($application->merchant) && isset($application->merchant->email)){
                            if (!in_array($application->merchant_id, explode(',', _env('NO_COMM_MERCHANT'))))
                                $cc_emails[] = $application->merchant->email;
                        }
                        if (isset($application->application_element) && isset($application->application_element->merchant_center)) {
                            foreach ($application->application_element->merchant_center as $center) {
                                if (isset($center->email) && !empty($center->email)) {
                                    $cc_emails[] = $center->email;
                                }
                            }
                        }
                    }

                    if (isset($application->email) && !empty($application->email) && UserEmails::isValid($application->email)) {
                        \Mail::send('emails.reminders.basic_reminder',
                            ['body' => $payload->body]
                            , function ($message) use ($application, $payload, $cc_emails) {
                                $message->to($application->email)->subject($payload->subject);
                                array_push($cc_emails,$payload->advisorEmail);
                                $cc_emails = array_unique($cc_emails);
                                if ($cc_emails) {
                                    $message->cc($cc_emails);
                                }
                            });
                    }

                    if (isset($payload->advisorSlack)){
                        (new Slack(new Request(['title' => $payload->subject, 'fields' => ['Content' => trim(strip_tags($payload->body))], 'group' => $payload->advisorSlack])))->send();
                    }
                }
            }else if($application->state == 'waiting for decision'){
                if(isset($payload->type) && $payload->type == 'credit'){
                    \Mail::send('emails.reminders.basic_reminder',
                        ['body' => $payload->body]
                        , function ($message) use ($payload) {
                            $message->to(['credit_team@creditfair.in'])->subject($payload->subject); //aditya@creditfair.in','imran@creditfair.in','shraddha@creditfair.in
                        });
                }
            }
        }catch (\Exception $exception){
            //var_dump($exception->getMessage().$exception->getLine());
            echo "Exception occured";
        }
    }

    public function sendEmail($data,$job){
        $application = ConsumerApplication::with('merchant')->where('id',$job->application_id)->whereIn('state',$this->status_array)->first(['email','mobile_number','state']);

            if (isset($application->email) && !empty($application->email) && UserEmails::isValid($application->email)) {
                \Mail::send('emails.blank',
                    ['body' => $data->body]
                    , function ($message) use ($application, $data) {
                        $message->to($application->email)->subject($data->subject);
                        if ($application->merchant && isset($application->merchant->email)) {
                            //$message->cc(explode(',', $application->merchant->email));
                        }
                    });

                $this->emailCount++;
            }
            if (isset($application->mobile_number) && !empty($application->mobile_number) && isset($data->sms)) {
                $mobile = '91' . $application->mobile_number;
                send_sms($mobile, ['message'=>$data->sms,'id'=>$job->application_id,'id_type'=>'application_id','message_type'=>"payment",  'templateId' => isset($data->templateId) ? $data->templateId : '', 'args' => isset($data->args) ? $data->args : '', 'templateDetails' => isset($data->templateDetails) ? $data->templateDetails : '']);
                $this->smsCount++;
            }
    }

    public function sendOps($error, $job){
        return (new Slack(new \Illuminate\Http\Request(['title' => 'Job Queue Error', 'fields' => ['trace' => json_encode($error),'jobs' => json_encode($job)], 'group' => Slack::$STAGE_TESTING])))->send();
        \Mail::send('emails.blank',
            ['body'=>$error,'job'=>$job]
            , function ($message) {
                $message->to('tech@creditfair.in')->subject('Error in queue');
                /*$message->cc(env('NOTIFY_EMAIL', ''));*/
            });
    }

    public function sendWaitReminder($job, $payload){
        if(isset($job->application_id)){
            $application = ConsumerApplication::where('id',$job->application_id)->whereNull('is_deleted')->whereIn('state',['form completed','incomplete form'])->first(['id']);

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

                if (isset($payload->name) && isset($payload->user_id)){
                    if ($payload->name == 'Advisors'){
                        $advisors = User::whereIn('user_type',[10,9])->whereNull('deleted_at')->get(['id']);
                        $users = [];
                        if ($advisors) {
                            foreach ($advisors as $advisor) {
                                $users[] = $advisor->id;
                            }
                        }
                        if (empty($users)){
                            $users = [29,36,1418,1968];
                        }
                    }else if ($payload->user_id > 0){
                        $users = [$payload->user_id];
                    }
                    if (isset($users) && $users) {
                        foreach ($users as $user) {
                            $userData = User::find($user);
                            if(isset($userData->mobile_number)) {
                                sendWhatsAppMessage($userData->mobile_number, str_replace('<br/>', "\n", str_replace('Advisors',$userData->name, $payload->body)));
                            }
                        }
                    }
                }
                if($payload->time == 20){
                    (new Slack(new Request(['title' => $payload->subject, 'fields' => ['Content' => strip_tags($payload->body)], 'group' => Slack::$application_reminder])))->send();
                }
            }
        }
    }

    public function anotherJobs(){
        (new EveryFiveMinutes())->missedOutboundCalls();
    }

    public static function addEntry($params) {
        event(new EventJobs($params));
    }
}
