<?php

namespace App\Http\Controllers\Admin;


use App\CampaignsJobProvider;
use App\Console\Commands\TallyBridge;
use App\Console\Commands\TallySettlement;
use App\ConsumerApplication;
use App\Events\V1\EventTallySubInt;
use App\Exports\Exporter;
use App\Http\Controllers\Controller;
use App\Imports\ExcelImport;
use App\Imports\TestImport;
use App\JobProvider;
use App\Lenders;
use App\Settlement;
use App\SettlementJobs;
use App\Slack;
use App\StaticPage;
use App\StatusLogs;
use App\Tally\Tally;
use App\Tally\TallyConnector;
use App\Tally\TallyJobs;
use App\TallyJobsListener;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Maatwebsite\Excel\Facades\Excel;
use App\EmiPayment;
use App\TallySettlementLogs;

class TallySettlementController extends Controller
{

    private $request;

    public function __construct(Request $request)
    {

        $this->request = $request;
    }

    public function getSettlements(){

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

        $from_date = $this->request->get('from_date') ? $this->request->get('from_date') : Carbon::now()->toDateString();
        $to_date = $this->request->get('to_date') ? $this->request->get('to_date') : Carbon::now()->toDateString();

        $settlements = Settlement::with('user')->where('reconciliation_date','>=',$from_date.' 00:00:00')->where('reconciliation_date','<=',$to_date.' 23:59:59')->whereNull('status')->orderBy('created_at','desc')->paginate(10);
        $status = 0;

        $connector = new TallyConnector();
        if ($connector->connect()){
            $status = 1;
        }

        $ledgers = $this->getLedgers();
        $lenders = Lenders::get();

        return view('admin.tally.settlement', ['settlements' => $settlements, 'from_date' => $from_date, 'to_date' => $to_date, 'status' => $status, 'ledgers' => $ledgers, 'lenders' => $lenders]);
    }

    public function fetchSubventionInterestApplicationsInternal(Request $request){
        if ($request->has('type') && $request->get('type') == 'subvention_and_interest') {
            $lender_id = !is_null($request->get('lender_id')) ? $request->get('lender_id') : 2;
            $emiDate = $request->get('emi_date');
            $emiDatesList = EmiPayment::where('emi_date', $emiDate)->get();
            $tallyLogDate = TallySettlementLogs::where('start_date', $emiDate)->where('lender_id', $lender_id)->get();

            if (count($emiDatesList) > 0 and count($tallyLogDate) == 0) {
                $tallyLog = new TallySettlementLogs();
                $tallyLog->type = $request->get('type');
                $tallyLog->user_id = $request->has('user_id') ? $request->get('user_id') : 107;
                $tallyLog->status = "pending";
                $tallyLog->start_date = $emiDate;
                $tallyLog->request = json_encode($this->request->all());
                $tallyLog->lender_id = $lender_id;
                $tallyLog->save();
                event(new EventTallySubInt($this->request->all()));
                return response()->json(['status' => 'OK', 'message' => 'Your request is in process. Kindly check slack for any update.']);
            } elseif (count($tallyLogDate) > 0) {
                if ($tallyLogDate->first()->status == 'pending') {
                    return response()->json(['status' => 'OK', 'message' => 'Subvention already initiated, please wait a while']);
                }
                return response()->json(['status' => 'OK', 'message' => 'Subvention interest already settled for the selected EMI date']);
            } else {
                return response()->json(['status' => 'OK', 'message' => 'Invalid date, please select valid EMI date']);
            }
        }

        if ($request->has('year') && $request->has('month') && $request->get('lender_id') && $request->get('type')){
            $tallyLog = new TallySettlementLogs();
            $tallyLog->type = $request->get('type');
            $tallyLog->user_id = $request->get('user_id');
            $tallyLog->status = "pending";
            $tallyLog->start_date = Carbon::parse($request->get('year').'-'.$request->get('month').'-01')->startOfMonth()->format('Y-m-d');
            $tallyLog->request = json_encode($this->request->all());
            $tallyLog->lender_id = $request->get('lender_id');
            $tallyLog->save();
            event(new EventTallySubInt($this->request->all()));
//            $this->startSubIntEntries($request);
            return response()->json(['status' => 'OK', 'message' => 'Your request is in process. Kindly check slack for any update.']);
        }
        return response()->json(['status' => 'FAIL', 'message' => 'Failed to run the job']);
    }

    public function startSubIntEntries($request){
        // bounce_penal = 13278, subventon_interest = 13274
        $type_of_entry = $request->has('type') ? $request->get('type') : '';

        $accounting = new AccountingController();
        //$data = $accounting->getAccruedProfitOnEmail(['year' => $request->get('year'), 'month' => $request->get('month'), 'lender_id' => $request->get('lender_id')]);
        if($type_of_entry == 'subvention_and_interest'){
            $Accrued_CWRC = $accounting->getSubventionInterest(['year' => $request->get('year'), 'month' => $request->get('month'), 'to_date' => $request->get('to_date'), 'emi_date' => $request->get('emi_date'), 'lender_id' => $request->get('lender_id')]);
        }else if($type_of_entry == 'bounce_and_penal'){
            $Accrued_CWRC = $accounting->getBouncePenalCharges(['year' => $request->get('year'), 'month' => $request->get('month'), 'lender_id' => $request->get('lender_id')]);
        }else{
            return 'false';
        }
//        (new Slack(new Request(['title' => 'Tally Settlement - Log 1', 'fields' => ['status' => 'charges calculated'], 'group'=>Slack::$TALLY_INTEGRATION])))->send();

        //$Accrued_CWRC = $data[0];

        $tallyDataSubInt = ['ID', 'EMI Date', 'Interest', 'Subvention'];
        $tallyDataBouncePenal = ['ID', 'EMI Date', 'Bounce Charges', 'Penal Interest'];
        foreach ($Accrued_CWRC as $item){

            if($type_of_entry == 'subvention_and_interest') {
                if ($item['interest'] > 0 || $item['subvention'] > 0) {
                    $tallyDataSubInt[] = [
                        $item['id'] ?? '',
                        $item['emi_date'] ?? '',
                        $item['interest'] ?? 0,
                        $item['subvention'] ?? 0,
                    ];
                }
            }

            if($type_of_entry == 'bounce_and_penal') {
                if ($item['Bounce Charges'] > 0 || $item['Penal Interest'] > 0) {
                    $tallyDataBouncePenal[] = [
                        $item['id'] ?? '',
                        $item['invoice_date'] ?? '',
                        $item['Bounce Charges'] ?? 0,
                        $item['Penal Interest'] ?? 0,
                    ];
                }
            }
        }

//        (new Slack(new Request(['title' => 'Tally Settlement - Log 2', 'fields' => ['status' => 'charges uploaded'], 'group'=>Slack::$TALLY_INTEGRATION])))->send();

        $import = new TestImport(new Request(['from' => __FUNCTION__]));
        if($type_of_entry == 'subvention_and_interest') {
            if (isset($tallyDataSubInt)) {
                $import->tallySubventionUpload($tallyDataSubInt);
            }
        }
        if($type_of_entry == 'bounce_and_penal') {
            if (isset($tallyDataBouncePenal)) {
                $import->bounce_panel_tally_entries($tallyDataBouncePenal);
            }
        }
//        (new Slack(new Request(['title' => 'Tally Settlement - Log 4', 'fields' => ['status' => 'After entry'], 'group'=>Slack::$TALLY_INTEGRATION])))->send();
    }

    public function fetchSettlementApplicationsInternal(){
        $settlement_date = $this->request->get('settlement_date') ? $this->request->get('settlement_date') : Carbon::now()->toDateString();
        $lender_id = $this->request->get('lender_id');

        $settlement_date_from = $settlement_date.' 00:00:00';
        $settlement_date_to = $settlement_date.' 23:59:59';
        $payments = DB::select("select consumer_application.id, consumer_application.name from payment_transactions left join consumer_application on consumer_application.id = payment_transactions.application_id where payment_date >= '$settlement_date_from' and payment_date <= '$settlement_date_to' and consumer_application.lender_id = '$lender_id' and payment_for = 'EMI' and status = 'success'");

        $ids = [];
        foreach ($payments as $payment){
            $ids[] = $payment->id;
        }

        $campIds = CampaignsJobProvider::where('from','tally_settlement_run')->whereIn('application_id', $ids)->get();

        $ids = [];
        foreach($campIds as $campId){
            $ids[] = $campId->application_id;
        }

        $response = '';
        foreach ($payments as $payment){
            $buttonClass = "settle-application-internal settle-application-'.$payment->id.' btn btn-primary";
            $buttonText = 'Settle';
            if (in_array($payment->id, $ids)){
                $buttonClass = "btn btn-success";
                $buttonText = 'Settled';
            }
            $response .= '<tr><td>'.$payment->id.'</td><td>'.$payment->name.'</td><td><div class="'.$buttonClass.'" data-id="'.$payment->id.'">'.$buttonText.'</div></td></tr>';
        }

        if ($response){
            return response()->json(['status' => 'OK', 'data' => $response]);
        }else{
            return response()->json(['status' => 'FAIL', 'message' => 'No Data']);
        }

    }

    public function internalSettlement(){

        $settlement_date = $this->request->get('settlement_date');
        $id = $this->request->get('application_id');

        $campIds = CampaignsJobProvider::where('from','tally_settlement_run')->where('application_id', $id)->first(['id']);
        if (isset($campIds->id)){
            return response()->json(['status' => 'FAIL', 'message' => 'Settlement already Started']);
        }

        $settlement_date_from = $settlement_date.' 00:00:00';
        $settlement_date_to = $settlement_date.' 23:59:59';

        $paymentReconcileData = [];
        $totalAmountReceived = 0;
        $is_started = false;

        if($settlement_date && $id) {
            $payments = DB::select("select * from payment_transactions where payment_date >= '$settlement_date_from' and payment_date <= '$settlement_date_to' and application_id = '$id' and payment_for = 'EMI' and status = 'success'");

            if(count($payments)) {
                foreach ($payments as $payment) {
                    if (isset($paymentReconcileData[$payment->application_id]) && $paymentReconcileData[$payment->application_id]['payment_reconciliation_date'] == $payment->payment_date) {
                        $paymentReconcileData[$payment->application_id]['amount'] += $payment->amount;
                    } else {

                        $paymentReconcileData[$payment->application_id] = [
                            'mode' => $payment->mode,
                            'paid_by' => '',
                            'application_id' => $payment->application_id,
                            'bank_id' => $payment->bank_id,
                            'umrn' => $payment->umrn,
                            'collected_by' => 107,
                            'trasanction_id' => $payment->trasanction_id,
                            'wallet_name' => '',
                            'payment_date' => $payment->payment_date,
                            'payment_reconciliation_date' => $payment->payment_date,
                            'amount' => $payment->amount,
                            'status' => $payment->status,
                            'reason' => '',
                            'trasanction_acknowledgement' => '',
                            'online_payment_id' => ''
                        ];
                    }

                    $totalAmountReceived += $payment->amount;
                }

                if ($paymentReconcileData) {
                    $paymentReconcileData = array_values($paymentReconcileData);
                    $subvention_only = $this->request->has('subvention_only') && $this->request->get('subvention_only') ? 1 : 0;
                    $settlement_id = Settlement::import(['data' => $paymentReconcileData, 'settled_amount' => $totalAmountReceived, 'payment_date' => $settlement_date, 'reconciliation_date' => $settlement_date, 'type' => 'nach', 'subvention_only' => $subvention_only]);
                    $is_started = true;
                }
            }
        }
        if ($is_started){

            if (isset($settlement_id)){
                $this->runSettlement($settlement_id, $id);
            }

            return response()->json(['status' => 'OK', 'message' => 'Settlement Started']);
        }else{
            return response()->json(['status' => 'FAIL', 'message' => 'Failed to start settlement, No Data Found']);
        }

    }

    public function razorPaySettlement(){
        $data = ['settlement_date' => $this->request->get('settlement_date') ? $this->request->get('settlement_date') : Carbon::now()->toDateString(), 'lender_id' => $this->request->get('lender_id')];
        (new TallyBridge())->importRazorPaySettlement($data);
        return response(['status' => 'OK', 'message' => 'Settlement under process please check slack for the update']);
    }

    public function payTMSettlement(){
        ini_set('max_execution_time', -1);
        set_time_limit(0);
        ini_set('memory_limit', '-1');

        $data = ['settlement_date' => $this->request->get('settlement_date') ? $this->request->get('settlement_date') : Carbon::now()->toDateString(), 'lender_id' => $this->request->get('lender_id')];
        (new TallyBridge())->importPayTMSettlement($data);
        return response(['status' => 'OK', 'message' => 'Settlement under process please check slack for the update']);
    }

    public function lotusPaySettlement(){
        $data = ['settlement_date' => $this->request->get('settlement_date') ? $this->request->get('settlement_date') : Carbon::now()->toDateString(), 'lender_id' => $this->request->get('lender_id')];
        $this->setLotusPaySettlement($data);
        return response(['status' => 'OK', 'message' => 'Settlement under process please check slack for the update']);
    }

    public function setLotusPaySettlement($data){
        $jobs = new CampaignsJobProvider();
        $jobs->from = 'tally_settlement_lotuspay';
        $jobs->payload = json_encode($data);
        $jobs->available_at = Carbon::now()->addMinutes(5)->toDateTimeString();
        $jobs->application_id = 181;
        $jobs->created_at = Carbon::now()->toDateTimeString();
        $jobs->is_available = 0;
        $jobs->save();
    }

    public function getLedgers(){
        $applicationsData = null;

        $statusLogs = StatusLogs::where('created_at' ,'>=', Carbon::now()->subDay(10)->startOfDay()->toDateTimeString())->where('status', 'disbursed')->get();

        $dates = [];
        foreach ($statusLogs as $log){
            $dates[] = $log->created_at;
        }

        usort($dates, function ($a, $b){
            return strtotime($a) - strtotime($b);
        });

        $newLedgers = [];
        if(isset($dates[0])) {
            $statusLogs = StatusLogs::where('created_at','>=',explode(' ',$dates[0])[0].' 00:00:00')->where('status', 'disbursed')->get();
            $newLedgers = [];
            foreach ($statusLogs as $log){
                if(!in_array($log->application_id, $newLedgers)){
                    $newLedgers[] = $log->application_id;
                }
            }
        }

        if($newLedgers) {
            $exists = TallyJobs::whereIn('application_id', $newLedgers)->where('payload','like','%LEDGER%')->get(['application_id']);
            $_newLedgers = [];
            foreach ($exists as $exist){
                $_newLedgers[] = $exist->application_id;
            }

            $__newLedgers = [];
            foreach ($newLedgers as $ledger__){
                if(!in_array($ledger__, $_newLedgers)) {
                    $__newLedgers[] = $ledger__;
                }
            }

            if($__newLedgers) {
                $applicationsData = ConsumerApplication::whereIn('id', $__newLedgers)->where('lender_id',2)->whereNull('is_deleted')->whereIn('state',['disbursed','closed','nach registered'])->get(['id', 'name']);
            }
        }

        return $applicationsData;
    }

    public function runSettlement($settlement_id, $id = 181){
        $jobs = new CampaignsJobProvider();
        $jobs->from = 'tally_settlement_run';
        $jobs->payload = json_encode(['settlement_id' => $settlement_id]);
        $jobs->available_at = Carbon::now()->toDateTimeString();
        $jobs->application_id = $id;
        $jobs->created_at = Carbon::now()->toDateTimeString();
        $jobs->is_available = 0;
        $jobs->save();

        $message = 'Settlement Started, You\'ll be notified on slack once settlement finished';
        Session::flash('success', $message);

        Settlement::where('id', $settlement_id)->update(['status' => 'Queue', 'user_id' => $this->request->get('user_id')]);

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

    public function runLedger(){
        if($this->request->has('ledgers')){
            $applications = ConsumerApplication::whereHas('logs')->whereNull('is_deleted')->where('lender_id',2)->whereIn('id', $this->request->get('ledgers'))->get();

            $isRun = false;
            foreach ($applications as $application){
                if (isset($application->logs) && $application->logs) {
                    $disbursed_date = Tally::getDisbursedDate($application->id);
                    TallyJobs::saveTally(['id' => $application->id, 'emi_date' => date('Y-m-d', strtotime($disbursed_date)), 'type' => 'LEDGER']);
                    $isRun = true;
                }
            }
            if($isRun) {
                $payload = [
                    'payload' => json_encode($this->request->all()),
                    'from' => 'tally',
                    'application_id' => 181,
                    'available_at' => Carbon::now()->addMinute(4)->toDateTimeString(),
                    'created_at' => Carbon::now()->toDateTimeString()
                ];
                JobProvider::insert($payload);
                return response(['status' => 'OK', 'message' => 'Ledger added in the queue']);
            }
        }

        return response(['status' => 'OK', 'message' => 'Can\'t add ledgers in the queue']);
    }

    public function exportSettlementApplications($id, $json = false){
        $settlement = Settlement::where('id', $id)->first();
        $response[] = ['ID', 'Name', 'Date', 'Source', 'Lender ID','Amount', 'UTR/Online Payment ID'];
        $total_amount = 0;
        if(isset($settlement->data)){
            $data = json_decode($settlement->data);
            foreach ($data->data as $item){
                $application = ConsumerApplication::where('id', $item->application_id)->first(['id','name','lender_id']);
                if ($application->lender_id == 2) {
                    $response[] = [
                        'id' => $item->application_id,
                        'name' => $application->name,
                        'date' => $settlement->payment_date,
                        'source' => $settlement->type,
                        'lender_id' => $application->lender_id,
                        'amount' => $item->amount,
                        'utr' => $item->online_payment_id ?? ''
                    ];

                    $total_amount += $item->amount;
                }
            }

            $response[] = ['','','','', 'Total Amount', $total_amount];
        }

        if ($json){
            return $response;
        }
        $request = new Request(['data' => $response, 'sheet' => 'Sheet1']);
        return Excel::download((new Exporter($request)), 'Repayment_'.Carbon::now()->toDateTimeString().'_'.$id.'.xls');
    }

    public function getSettlementApplications(){
        $settlement = Settlement::where('id', $this->request->get('id'))->first();
        $response = '';
        if(isset($settlement->data)){
            $data = json_decode($settlement->data);
            $response = '<table class="table"><tr><th>ID</th><th>Name</th><th>Bank</th><th>Transaction ID</th></tr>';
            foreach ($data->data as $item){
                $application = ConsumerApplication::where('id', $item->application_id)->first();
                $response .= '<tr><td>'.$item->application_id.'</td><td>'.$application->name.'</td><td></td><td>'.$item->trasanction_id.'</td></tr>';
            }
            $response .= '</table>';
        }

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

    public function importExcelToXMLExport($id){
        Excel::import(new ExcelImport(new Request()), $this->request->file('excel_file_payment'));
    }

    public function proceedLocally($id){
        Settlement::where('id', $id)->update(['status' => 'Success', 'user_id' => $this->request->get('user_id'), 'is_available' => 1]);
        return response()->json(['status' => 'OK'], 200);
    }

    public function excelToXMLExport($id){
        $collection = collect($this->exportSettlementApplications($id, true));
        $excelImport = new ExcelImport(new Request());
        return $excelImport->collection($collection);
    }
}
