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

namespace App\Console\Commands;


use App\Capri;
use App\ConsumerApplication;
use App\ConsumerApplicationElement;
use App\EmiPayment;
use App\Http\Controllers\Admin\ConsumerApplicationController;
use App\Http\Controllers\Admin\EMICalculation;
use App\Jobs;
use App\PaymentTransaction;
use App\Services;
use App\Singularity\Singularity;
use App\Slack;
use App\Vivriti;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Http\Request;

class AdvanceReminders extends Command
{

/*1 - non-nach morning
2 no mails
3 mornging nach (non nach both work)
4 non nach working
5 mornging nach (non nach both work)


14 - non - nach mornign
15 no mails
16 mornging nach (non nach both work)
17 non nach working
18 mornging nach (non nach both work)*/

    protected $signature = 'advanceEMI:dueReminder {--emi_date=} {--nach=} {--bypass=} {--slot=} {--application_id=}';
    private $emi_date = false;
    private $send_nach = 2;
    private $bypass = 0;
    private $morning = '09';
    private $evening = '18';
    private $slot = '';
    private $application_id = "";
    private $hour = "";
    private $job = false;
    public $stopCommunication = [8378];


    public function __construct(){
        parent::__construct();
    }


    public function handle($payload = array()){

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

        $this->hour = date('H',time());
        if (\app()->runningInConsole() && !isset($payload->emi_date)) {
            $this->bypass = $this->option('bypass');
        }

        if($payload && isset($payload->emi_date)){
            $this->emi_date = $payload->emi_date;
            $this->send_nach = $payload->send_nach;
            $this->slot = $payload->slot;
            $this->application_id = isset($payload->application_id) ? $payload->application_id : "";
            $this->bypass = 1;
            $this->job = true;
        }

        if($this->hour == $this->morning || $this->hour == $this->evening || $this->bypass) {
            if (\app()->runningInConsole() && !$this->job) {
                $this->emi_date = $this->option('emi_date');
                $this->send_nach = $this->option('nach');
                $this->slot = $this->option('slot');
                $this->application_id = $this->option('application_id');
            }else if (empty($this->slot)){
                if($this->hour == $this->evening){
                    $this->slot = 'evening';
                }elseif($this->hour == $this->morning){
                    $this->slot = 'morning';
                }
            }
            $this->getReminders();
        }else{
            return true;
        }
    }

    public function isQueueable($schedules){
       // if ($this->emi_date)
            //return true;
        $schedule = array_reverse($schedules['schedule']);
        for ($i = 0; $i <= count($schedule); $i++){
            if (isset($schedule[$i])) {
                $date = Carbon::createFromFormat('Y-m-d', $schedule[$i])->toDateString();
                if (Carbon::now()->toDateString() == $date){
                    return true;
                }
            }
        }

        return false;
    }

    public function getReminders(){

        $start_time = time();
        $serviceStatus = false;
        $serviceCount = 0;
        $emailCountnNach = 0;
        $emailCountNonNach = 0;
        $smsCountNonNach = 0;
        $smsCountNach = 0;

        $applications = ConsumerApplication::with('mandateMany')->whereNull('is_deleted')->whereIn('state',['disbursed','nach registered'])->whereNotIn('merchant_id',[6418,6517,6598,6865,6600,6746,6754])->where('id','!=',101);
        if($this->application_id != ""){
            $applications = $applications->where('id',$this->application_id);
        }
        $lender_id = Singularity::$lender_id;

        if($lender_id){
            $applications = $applications->whereNotIn('lender_id', [$lender_id, Capri::$lender_id, Vivriti::$lender_id]);
        }

        if($this->stopCommunication){
            $applications = $applications->whereNotIn('merchant_id', $this->stopCommunication);
        }

        $applications->select('id', 'merchant_id')->chunk(1000, function ($applications) use(&$start_time, &$serviceStatus, &$serviceCount, &$emailCountnNach, &$emailCountNonNach, &$smsCountNonNach, &$smsCountNach) {
            $consumerApplicationController = new ConsumerApplicationController();
            foreach ($applications as $application) {
                try {
                    $skip_reminder = false;
                    $element = ConsumerApplicationElement::where('application_id', $application->id)->first(['foreclosure_date', 'last_emi_date']);
                    if (isset($element->foreclosure_date) && strlen($element->foreclosure_date) > 0) {
                        $is_foreclosed = PaymentTransaction::where('application_id', $application->id)->where('payment_for', 'Foreclosure')
                            ->whereNull('deleted_at')->whereNull('is_deleted_at')->whereNull('deleted_by')->first();
                        if (isset($is_foreclosed->id) && $is_foreclosed->id) {
                            $skip_reminder = true;
                        }
                    }

                    if (isset($element->last_emi_date) && strtotime($element->last_emi_date) < Carbon::now()->timestamp) {
                        $skip_reminder = true;
                    }

                    if (!$skip_reminder) {
                        if ($schedules = $this->checkReminder($application, $consumerApplicationController)) {
                            if ($this->isPaymentReceived($application->id, $schedules)) {
                                //if($this->isQueueable($schedules)) {
                                if (!$this->job) {
                                    $this->comment('Sending ' . $application->id);
                                }
                                $job = new \stdClass();
                                $job->application_id = $application->id;
                                $job->from = 'emiDueReminder';
                                $jobObject = (new Jobs());
                                $jobObject->queue($job, $consumerApplicationController, $schedules['payload']);
                                $serviceStatus = true;
                                if (isset($schedules['mandate']) && $schedules['mandate'] == 1) {
                                    $emailCountnNach += $jobObject->emailCount;
                                    $smsCountNach += $jobObject->smsCount;
                                } else {
                                    $emailCountNonNach += $jobObject->emailCount;
                                    $smsCountNonNach += $jobObject->smsCount;
                                }
                                if (!$this->job) {
                                    $this->comment(json_encode($schedules['payload']) . "\n");
                                }
                                //}
                            }
                        }
                    }
                    $serviceCount++;
                } catch (\Exception $e) {
                    (new Slack(new Request(['title' => 'Monthly EMI Reminder Error', 'fields' => ['ID' => $application->id, 'Message' => $e->getMessage(), 'File' => $e->getFile(), 'Line' => $e->getLine()]])))->send();
                }
            }
        });

        if($serviceStatus)
            (new Services())->log('EMIDueReminder', ['status' => true, 'service_count' => $serviceCount, 'start_time' => $start_time]);
        if ($emailCountnNach || $smsCountNonNach || $emailCountNonNach || $smsCountNach)
            (new Slack(new Request(['title'=>'Monthly EMI Reminder Summary','fields'=>['Total Nach Email Sent'=>$emailCountnNach,'Total Nach SMS Sent'=>$smsCountNach,'Total Non Nach Email Sent'=>$emailCountNonNach,'Total Non Nach SMS Sent'=>$smsCountNonNach], 'group' => 'payment_collection'])))->send();
    }

    public function isPaymentReceived($id, $schedule){
        $paymentTransaction = EmiPayment::with('transaction')->where('payment_status','success')->where('application_id',$id)->where('due_date', $schedule['payload']->emi_date)->first();
        if (isset($paymentTransaction) && $paymentTransaction->transaction){
            return false;
        }else{
            $paymentTransaction = EmiPayment::with('transaction')->where('payment_status','success')->where('application_id',$id)->where('emi_date', $schedule['payload']->emi_date)->first();
            if (isset($paymentTransaction) && $paymentTransaction->transaction){
                return false;
            }
        }
        return true;
    }

    public function checkReminder($application, ConsumerApplicationController $consumerApplicationController){
        //$consumerApplication = ConsumerApplication::with('merchant','bank_details','emi','proFormaInvoice','mandateMany')->find($application->id);
        $data =  (new EMICalculation(new Request()))->generateAdvanceDues($application->id, false, false);
        $mandate = $consumerApplicationController->isMandateActive($application);
        if (!$mandate){
            $mandate = $consumerApplicationController->isMandateActive($application, 'accepted');
        }
        if($this->slot == 'morning'){
            $days_to_send = ($mandate == 0) ? array(4,2,1,0) : array(2,0);
        }else{
            $days_to_send = ($mandate == 0) ? array(2,1,0) : array();
        }
        $now = Carbon::now();
        $scheduleData = [];
        $emiDates = [];
        $existingEMIs = [];
        foreach ($data['payload'] as $item){
            $payload = json_decode($item['payload']);
            $emiDates[] = strtotime($payload->emi_date);

            $existingEMIs[$payload->emi_date] = $payload;
        }

        $nexEMIDate = date('Y-m-d',$this->getNextEMI($now->timestamp, $emiDates));

        $date = Carbon::parse($nexEMIDate);

        $daysRemaining = $date->diffInDays($now->toDateString());


        if ($this->emi_date){
            if (isset($existingEMIs[$this->emi_date])) {
                if ($this->send_nach == 0){
                    if($mandate == 0){
                        $scheduleData[] = $this->emi_date;
                        $nexEMIDate = $this->emi_date;
                    }
                }else if ($this->send_nach == 1){
                    if($mandate == 1){
                        $scheduleData[] = $this->emi_date;
                        $nexEMIDate = $this->emi_date;
                    }
                }else if ($this->send_nach == 2){
                    $scheduleData[] = $this->emi_date;
                    $nexEMIDate = $this->emi_date;
                }
                /*if ($this->send_nach) {
                    $scheduleData[] = $this->emi_date;
                    $nexEMIDate = $this->emi_date;
                }else if($mandate == 0){
                    $scheduleData[] = $this->emi_date;
                    $nexEMIDate = $this->emi_date;
                }*/
            }
        }else{
            if(in_array($daysRemaining,$days_to_send)){
                $availableDate = Carbon::parse($nexEMIDate)->subDay($daysRemaining)->toDateString();
                if (strtotime($availableDate) <= strtotime($nexEMIDate) && !in_array($availableDate, $scheduleData) && $availableDate == Carbon::now()->toDateString()) {
                    $scheduleData[] = $availableDate;
                }
            }
            $scheduleData = array_values(array_slice($scheduleData, 0, 5, true));
        }

        //return false;
        return !empty($scheduleData) && isset($existingEMIs[$nexEMIDate]) ? [
            'payload' => isset($existingEMIs[$nexEMIDate]) ? $existingEMIs[$nexEMIDate] : [],
            'schedule' => $scheduleData,
            'mandate' => $mandate
        ] : false;
    }

    function getNextEMI($search, $arr) {
        $closest = null;
        foreach ($arr as $item) {
            if ($closest === null || abs($search - $closest) > abs($item - $search)) {
                $closest = $item;
            }
        }
        return $closest;
    }
}
