<?php

namespace App\Http\Controllers;

use Carbon\Carbon;
use App\Models\Pop;
use App\Models\User;
use App\Models\Client;
use App\Models\Income;
use App\Models\Balance;
use App\Models\Employee;
use App\Classes\AuthUser;
use App\Classes\BkashUser;
use App\Models\IncomeHead;
use App\Models\Billpayment;
use App\Models\Clientsinfo;
use App\Models\BillGenerate;
use App\Models\BkashPayment;
use App\Models\BankTransfar;
use Illuminate\Http\Request;
use App\Classes\Notification;
use App\Services\ExpireCheck;
use App\Models\UserAccounting;
use App\Classes\SMS\PaymentSms;
use App\Models\CustomerAccount;
use App\Jobs\SendPaymentMailJob;
use App\Services\ClientServices;
use App\Models\BalanceAdjustment;
use App\Models\CompanyInformation;
use Illuminate\Support\Facades\DB;
use App\Services\CommissionService;
use App\Services\CommissionCalculationService;
use App\Jobs\ClientSyncJobForSingle;
use Brian2694\Toastr\Facades\Toastr;
use App\Services\GenerateMonthlyBill;
use App\Models\ReselleBalanceLogReport;
use Illuminate\Support\Facades\Session;
use App\Models\SubResellerBalanceLogReport;
use App\Http\Controllers\Clients\IdEnableDisableController;
use App\Http\Controllers\Reseller\ResellerRechargeController;
use App\Jobs\BillGenerateUpdateJob;
use App\Models\OtcPaymentLog;
use App\Models\Packages;
use App\Models\Reseller;
use App\Models\ResellerCommissionReference;
use App\Models\ResellerRechargeReport;
use App\Models\SubResellerCommissionReference;
use App\Services\ExpirationService;
use App\Services\ExpireDateRoundService;
use App\Services\RadiusClientSync;
use App\Services\SecondMonthlyBillGenerateForDayToDay;
use Exception;
use Illuminate\Support\Facades\Log;
use League\CommonMark\Extension\SmartPunct\EllipsesParser;

class PaymentController extends Controller
{

    public function getPaymentHistory($id)
    {
        if (!auth()->user()->hasPermissionTo('payment-report')) {
            return redirect()->back()->with('error_message', 'Permission Error!');
        }

        $list = ClientServices::customerList('singleUser', $id);

        if (!isset($list->first()->bill_generate) || $list->first()->bill_generate == 'no') {
            Toastr::error('User History Not available', 'error');
            return redirect()->back();
        }


        return view('billing.payment', [
            'list'               => $list->get(),
            'page_title'         => 'View Payment History',
            'employees'          => Employee::all(),
            'incomeHead'         => IncomeHead::all(),
            'paymenthistory'     => Billpayment::with('user', 'income', 'employee')->whereClient_id($id)->orderBy('id', 'desc'),
            'bill_history'       => BillGenerate::whereClient_id($id)->orderBy('id', 'desc'),
            'balance_adjustment' => BalanceAdjustment::with('user')->where('client_id', $id)->orderBy('id', 'desc')->take(10)

        ]);
    }

    public function paymentLog($id)
    {
        return view('paymenthistory.paymentLog', [
            'paymenthistory'    => Billpayment::with('user', 'income', 'employee')->whereClient_id($id)->orderBy('id', 'desc'),
        ]);
    }

    public function clientAccount($id)
    {
        $r = CustomerAccount::where('client_id', $id)->first();

        $due = $r->dueAmount > 0 ? $r->dueAmount : 0;
        $currentbalance = $r->dueAmount < 0 ? abs($r->dueAmount) : 0;
        $otc_due = Clientsinfo::where('client_id', $id)->first()->otc_due ?? 0;
        $client = Client::find($id);


        if ($client->clients_status == 'active') {
            $status = 'Active';
            $class = 'bg-success';
        } elseif ($client->clients_status == 'deactive') {
            $status = 'Deactive';
            $class = 'bg-secondary';
        } elseif ($client->clients_status == 'expired') {
            $status = 'Expired';
            $class = 'bg-danger';
        } elseif ($client->clients_status == 'disable') {
            $status = 'Disabled';
            $class = 'bg-warning';
        }


        return response()->json([
            'totalPaidAmount'       => $r->totalPaid,
            'totalDueAmount'        => $due,
            'totalCurrentAmount'    => $currentbalance,
            'totalOtcAmount'        => $otc_due,
            'cStatus'               => $status,
            'listDue'               => $r->dueAmount,
            'cExpireDate'           => Carbon::parse($client->expire_date)->format('d-M-Y'),
            'class'                 => $class,
        ]);
    }




    public function payment($id)
    {


        if (!auth()->user()->hasPermissionTo('money-receipt-entry')) {
            return redirect()->route('clients.index')->with('error_message', 'Permission Error!');
        }

        $list = ClientServices::customerList('singleUser', $id);

        return view('billing.payment', [
            'list'              => $list->get(), //Client::with('clientsinfo','packages','pop')->paginate(5),
            'page_title'        => 'View Payment Information',
            'paymenthistory'    => Billpayment::with('user')->whereClient_id($id)->orderBy('id', 'desc'),
            'pagetype'          => 'payment',
            'incomeHead'        => IncomeHead::all(),
            'employees'         => Employee::all(),
            'bill_history'      => BillGenerate::whereClient_id($id)->orderBy('id', 'desc')->take(25)
        ]);
    }

    public function balanceAdjustment(Request $request)
    {

        $client = Client::with('customerAccount')->where('id', $request->client_id)->first();

        DB::beginTransaction();


        try {

            if (!$client->customerAccount->isDueAmountNegative || abs($client->customerAccount->dueAmount) < $request->amount || $request->amount <= 0) {
                DB::commit();
                Toastr::error('Sorry not permitted', 'error');
                return redirect()->back();
            }

            BalanceAdjustment::create([
                'amount'        => $request->amount,
                'description'   => $request->description,
                'user_id'       => auth()->user()->id,
                'client_id'     => $request->client_id
            ]);

            $customerAccounts = CustomerAccount::find($client->customerAccount->id);
            $customerAccounts->increment('dueAmount', $request->amount);

            DB::commit();
            Toastr::success('Balance Adjust Successfull', 'success');
            return redirect()->back();
        } catch (\Throwable $th) {

            DB::rollBack();
            Toastr::error('Something is wrong!!', 'error');
            return redirect()->back();
        }
    }



    public function checkLastPaymentTimeForThisUser($id)
    {
        $t = Billpayment::where('client_id', $id)
            ->latest('id')
            ->first();

        if ($t !== null) {
            $now = now();
            $last_entry = $t->created_at;

            if ($last_entry->diffInMinutes($now) < 2) {
                return 2 - $last_entry->diffInMinutes($now);
            }
        }
    }


    public function autoPayment($client_id, $bill_amount, $type, $incomeHeadId)
    {

        $receipt_id =  'AT' . today()->timestamp . round($bill_amount);

        $data = [
            'description'           =>  $type . ' Bill Collection',
            'paid_amount'           =>  $bill_amount,
            'discount_amount'       =>  0,
            'client_id'             =>  $client_id,
            'user_id'               =>  auth()->id(),
            'created_at'            =>  now(),
            'collected_by'          =>  0,
            'money_receipt_number'  =>  $this->generateUniqueId($client_id, $bill_amount),
            'payment_mthod'         =>  'cash',
            'client_id_time'        =>  $client_id . '_AT_' . now()->addMinute()->format('Y-m-d H:i')
        ];
        $payment = Billpayment::create($data);

        $income_type = IncomeHead::find($incomeHeadId);

        $income =   Income::create([
            'name' => $income_type->name,
            'date' => now(),
            'amount' => $bill_amount,
            'description' => 'Bill Payment for customer : ' . Client::find($client_id)->userid,
            'incomeHead' => $incomeHeadId
        ]);
        $payment->income_id = $income->id;
        $payment->save();

        $actions = 'Bill Payment. cost ' . $bill_amount . 'TK for the customer ' . $client_id;
        $UserAccounting = UserAccounting::userAcStore($bill_amount, $actions, $client_id);
        $payment->user_accountings_id = $UserAccounting->id;

        CustomerAccount::updateCustomrAccount($client_id, (-$bill_amount), $bill_amount, 0);
    }

    public function generateUniqueId($client, $bill_amount)
    {
        return 'AT' . now()->timestamp . round($bill_amount) . $client;
    }

    public function newUserPaymentProcess($id)
    {

        $billinfo = BillGenerate::where('client_id', $id)->first();


        if ($billinfo) {

            $client = Client::with('clientsinfo')->where('id', $id)->first();


            $data = [
                'description'           =>  'New User Bill Collection',
                'paid_amount'           =>  $billinfo->bill_amount,
                'discount_amount'       =>  0,
                'client_id'             =>  $id,
                'user_id'               =>  auth()->id(),
                'created_at'            =>  now(),
                'collected_by'          =>  0,
                'money_receipt_number'  =>  $this->generateUniqueId($client->id, $billinfo->bill_amount),
                'payment_mthod'         =>  'cash',
                'client_id_time'        =>  $id . '_' . now()->format('Y-m-d H:i')
            ];
            $payment = Billpayment::create($data);

            $income_type = IncomeHead::find(1);

            $income =   Income::create([
                'name' => $income_type->name,
                'date' => now(),
                'amount' => $billinfo->bill_amount,
                'description' => 'Bill Payment for customer : ' . $client->userid,
                'incomeHead' => 1
            ]);
            $payment->income_id = $income->id;
            $payment->save();


            CustomerAccount::updateCustomrAccount($id, (-$billinfo->bill_amount), $billinfo->bill_amount, 0);

            $cac = CustomerAccount::where('client_id', $id)->first();
        }
    }

    public function newUserOTCPaymentProcess($id, $otc, $income_id)
    {

        $client = Client::with('clientsinfo')->where('id', $id)->first();

        $receipt_id =  'AT' . today()->timestamp . round($otc);

        $data = [
            'description'           =>  'OTC Collection',
            'paid_amount'           =>  $otc,
            'discount_amount'       =>  0,
            'client_id'             =>  $id,
            'user_id'               =>  auth()->id(),
            'created_at'            =>  now(),
            'collected_by'          =>  0,
            'money_receipt_number'  =>  $this->generateUniqueId($client->id, $otc),
            'income_id'             => $income_id,
            'payment_mthod'         =>  'cash',
            'client_id_time'        =>  $id . '_OTC_' . now()->format('Y-m-d H:i')
        ];
        $payment = Billpayment::create($data);

        CustomerAccount::updateCustomrAccount($id, (-$otc), $otc, 0);
    }

    public function getClient($id)
    {
        $client = Client::with('clientsinfo', 'pop', 'pop.reseller', 'customerAccount', 'packages', 'subpack')
            ->with(['generatedBill' => function ($q) {
                $q->whereBetween('created_at', [today()->startOfDay(), today()->endOfDay()])->where('billing_type', '!=', 'deleted');
            }])
            ->withCount('generatedBill')->find($id);

        return $client;
    }

    private function generateMonthlyBillIfNotExist($client_id)
    {
        $bill = BillGenerate::where('client_id', $client_id)
            ->whereBetween('created_at', [today()->startOfDay(), today()->endOfDay()])
            ->where('billing_type', 'monthly')
            ->first();

        if (!$bill) {
            $user = Client::find($client_id);
            (new GenerateMonthlyBill)->generate($user);

            if (getBillingType() === 'day_to_day' && $user->expire_date < today()) {
                $user->expire_date = today();
                $user->billing_cycle = date('d');
                $user->save();
            }
        }
    }

    private function single_bill_amount_for_day_to_day($client, $payment_day)
    {
        $amount = $client->packages->package_rate - $client->parmanent_discount;
        return round(($amount / 30) * $payment_day);
    }


    public function billGenerateIfNotExist($client_id, $payment_day = null)
    {
        $client = Client::find($client_id);
        if (checkSettings('auto-bill-generate-on-payment') == 'enable') {

            if ($payment_day && $payment_day == 30) {
                $this->generateMonthlyBillIfNotExist($client_id);
            } elseif ($payment_day) {

                $client = Client::with('packages', 'clientsinfo')->find($client_id);
                $bill_amount = $this->single_bill_amount_for_day_to_day($client, $payment_day);
                $note = 'Bill payment for ' . $payment_day . ' days';
                $bill_type = 'day_to_day';
                CustomerAccount::updateCustomrAccount($client_id, $bill_amount, 0, 0, $bill_amount);
                BillGenerateController::entryBillGenerate($client_id, $bill_amount, $note, $bill_type, today());
            } else {
                $this->generateMonthlyBillIfNotExist($client_id);
            }
        }
    }





    public function paymentprocess(Request $request)
    {


        if (!auth()->user()->hasPermissionTo('money-receipt-entry')) {
            return response()->json([
                'status' => 'error',
                'message' => 'Permission Error!!'
            ]);
        }
        if ($request->collected_by == null) {
            return response()->json([
                'status' => 'error',
                'message' => 'Please select Collected By!'
            ]);
        }

        if ($request->discount != null && $request->amount == null) {
            return response()->json([
                'status' => 'error',
                'message' => 'Amount must be 0 or greater than 0'
            ]);
        }

        $this->billGenerateIfNotExist($request->id, $request->payment_day);

        $client = $this->getClient($request->id);

        if (getBillingType() === 'day_to_day' && $request->amount + $request->discount < 1) {

            if ($request->payment_day) {
                $amount = round(($client->packages->package_rate / 30) * $request->payment_day);
            } else {
                $amount = $client->packages->package_rate;
            }
            $request->request->add(['amount' => $amount]);
        } elseif ($request->amount + $request->discount < 1) {

            return response()->json([
                'status' => 'error',
                'message' => 'Amount must be greater than 0'
            ]);
        }

        if (!$request->payment_day) {
            $request->merge(['payment_day' => 30]);
        }

        if ($request->amount < 1 && $request->discount > 0 && $request->payment_type  == 2) {
            return response()->json([
                'status' => 'error',
                'message' => 'OTC must be greter then 0'
            ]);
        }


        if (!empty($request->money_receipt_number)) {
            if (Billpayment::where('money_receipt_number', $request->money_receipt_number)->first() != null) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Duplicate MR ID'
                ]);
            }
            $receipt_id = $request->money_receipt_number;
        } else {
            if (checkSettings('money_receipt_no_required') == 'enable') {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Money Receipt No is required'
                ]);
            } else {
                $receipt_id =  $this->generateUniqueId($client->id, $request->bill_amount);
            }
        }


        $current_due_amount = $client->customerAccount->dueAmount ?? 0;


        if ($request->payment_type == 2 && $client->clientsinfo->otc_due < $request->amount) {
            return response()->json([
                'status' => 'error',
                'message' => 'OTC must be same as Due OTC'
            ]);
        }

        if ($this->checkLastPaymentTimeForThisUser($client->id) > 0) {
            return response()->json([
                'status' => 'error',
                'message' => 'Please Try After ' . $this->checkLastPaymentTimeForThisUser($client->id) . ' Minutes.'
            ]);
        }

        if (globalPermission('payment-bill-by-bill')) {

            if ($request->bill_ids == null) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Not bill found please try again'
                ]);
            }

            $bill = BillGenerate::find($request->bill_ids);
            $total_amount = ($request->amount ?? 0) + ($request->discount ?? 0);
            if ($bill->bill_amount < ($total_amount + $bill->paid_amount)) {

                return response()->json([
                    'status' => 'error',
                    'message' => 'Bill amount is smaller than payment amount'
                ]);
            }
        }

        DB::beginTransaction();

        try {


            $due_adjust_amount = $request->amount ?? 0 + $request->discount ?? 0;

            $month = $request->month;


            $data = [
                'description'           =>  $request->description ?? ' Bill Collection',
                'paid_amount'           =>  $request->amount ?? 0,
                'discount_amount'       =>  $request->discount ?? 0,
                'client_id'             =>  $request->client_id,
                'user_id'               =>  auth()->user()->id,
                'created_at'            =>  now(),
                'collected_by'          =>  $request->collected_by,
                'money_receipt_number'  =>  $receipt_id,
                'expire_date_history'   =>  $client->expire_date,
                'payment_method'        =>  'cash',
                'client_id_time'        =>  $request->client_id . '_' . now()->format('Y-m-d H:i')

            ];

            $payment = Billpayment::create($data);


            if (globalPermission('payment-bill-by-bill')) {
                $payment->bill_ids = $request->bill_ids;
                $payment->save();

                $bill_generate = BillGenerate::find($request->bill_ids);
                $total_amount = ($request->amount ?? 0) + ($request->discount ?? 0) +  ($bill_generate->paid_amount ?? 0);
                $bill_generate->paid_amount = $total_amount;
                $bill_generate->save();
            }

            CustomerAccount::updateCustomrAccount(
                $request->client_id,
                (-$request->amount),
                $request->amount,
                $request->discount ?? 0
            );

            if ($client->pop->reseller->reseller_type == 'own') {
                $actions = 'Bill Payment. cost ' . $due_adjust_amount . 'TK for the customer ' . $client->userid;
                $UserAccounting = UserAccounting::userAcStore($request->amount, $actions, $client->id);
                $payment->user_accountings_id = $UserAccounting->id;
            }

            $income_type = IncomeHead::find($request->payment_type);
            $income =   Income::create([
                'name' => $income_type->name,
                'date' => now(),
                'amount' => $request->amount,
                'description' => 'Bill Payment for customer : ' . $client->userid,
                'incomeHead' => $request->payment_type,
                'bank_account_id' => !empty($request->bank_account_id) ? $request->bank_account_id : null
            ]);
            $payment->income_id = $income->id;
            $payment->save();

            // Check if bank account is selected
            if ($request->filled('bank_account_id') && !empty($request->bank_account_id)) {
                // Deposit to bank account
                $bankDeposit = new BankTransfar();
                $bankDeposit->account_id = $request->bank_account_id;
                $bankDeposit->diposit_amount = $request->amount;
                $bankDeposit->description = 'Bill Payment [Payment ID:' . $payment->id . ']: Customer ' . $client->userid . ' - ' . ($request->description ?? 'Bill Collection');
                $bankDeposit->by = auth()->user()->name ?? 'System';
                $bankDeposit->save();
            }


            if ($request->payment_type == 2) {
                $clientinfo = clientsinfo::where('client_id', $client->id)->first();
                $clientinfo->otc_due = $clientinfo->otc_due - ($request->amount + $request->discount);
                $clientinfo->save();
            }

            $cac = CustomerAccount::where('client_id', $client->id)->first();
            //kalam
            $st = $this->performeExpireDateExtend($client, $payment, $cac, $request->amount, $client->pop, $current_due_amount, '', $request->discount, $request->payment_day);

            if ($st == 'balance_error') {
                $pop = Pop::where('id', $client->pop_id)->first();

                if ($pop->subreseller == 'yes') {
                    return response()->json([
                        'status' => 'error',
                        'message' => ' এর ব্যালেন্স নাই'
                    ]);
                } else {
                    return response()->json([
                        'status' => 'error',
                        'message' => 'ম্যানেজার এর ব্যালেন্স নাই'
                    ]);
                }
            }

            DB::commit();

            if (globalPermission('RadiusExpiration')) {
                try {
                    (new ExpirationService())->handleExpiration($client->userid, $client->expire_date, $client->payment_dadeline, $client->pop->experity_check);
                } catch (\Exception $exce) {
                }
            }

            try {
                if (!globalPermission('payment-bill-by-bill')) {
                    BillGenerateUpdateJob::dispatch($client->id);
                }
            } catch (\Exception $e) {
            }

            try {

                if ($request->sms == 'true') {

                    if ($client->pop->sms_send == 'yes') {

                        $cac = CustomerAccount::where('client_id', $client->id)->first();
                        $totalDue = $cac->dueAmount < 0 ? 0 : $cac->dueAmount;
                        (new PaymentSms)->billPaymentSms($this->getClient($request->id), $request->amount, $receipt_id, $payment->id, 'Cash', $request->discount ?? 0, $totalDue ?? 0, $request->description, $request->payment_type);
                    }
                }
            } catch (\Exception $e) {
            }

            try {

                $emailSetting = json_decode(emailSetting()->where('tamplate_name', 'customer_payment_eamil')->first()->email_body);
                if ($emailSetting->sendemail == 'Yes') {
                    SendPaymentMailJob::dispatch($client, $payment, $emailSetting);
                }
            } catch (\Exception $e) {
            }

            try {
                (new Notification)->notify("..::[Bill Payment]::..\n Payment By: " .
                    auth()->user()->name . " \nUsername : " .
                    $client->userid . " \nPassword : " . $client->password . "\nAmount: " . $request->amount . "\nReceipt ID: " . $receipt_id . "\nDescription: " . $request->description, $client->pop->reseller->reseller_type);
            } catch (\Exception $e) {
            }

            try {

                if (checkAPI()) {
                    ClientSyncJobForSingle::dispatch($client->id);
                }
            } catch (\Exception $e) {
            }


            return response()->json([
                'status' => 'success',
                'message' => 'Payment Done!!',
                'payment_id' => $payment->id
            ]);
        } catch (\Throwable $th) {
            DB::rollback();
            return response()->json([
                'status' => 'error',
                'message' => 'Something Is wrong Please check on customer payment ' . $th
            ]);
        }
    }




    public function billPayPayment($trxid, $client_id, $amount, $mobile, $datetime, $type, $billpay = '')
    {
        if ($trxid && $client_id && $amount && $mobile) {

            $this->billGenerateIfNotExist($client_id);


            $payment = Billpayment::where('money_receipt_number', $type . '_' . $trxid)->first();

            if ($payment == null) {


                try {
                    $client = Client::with('clientsinfo', 'pop', 'pop.reseller:id,billable,reseller_type', 'customerAccount')
                        ->withCount('generatedBill')
                        ->where('id', $client_id)->withTrashed()
                        ->first();

                    DB::transaction(function () use ($client_id, $type, $trxid, $mobile, $datetime, $amount, $client, $billpay) {
                        // Log::error("after transaction id ". $client_id);

                        $client = Client::with('clientsinfo', 'pop', 'pop.reseller:id,billable,reseller_type', 'customerAccount')
                            ->withCount('generatedBill')
                            ->where('id', $client_id)->withTrashed()
                            ->first();


                        $current_due_amount = $client->customerAccount->dueAmount;



                        $user = (new AuthUser)->check('user@' . $type . '.com', $type);


                        $data = [
                            'description'           =>  'Bill Payment from bill pay (' . $type . ') Bill Month : ' . today()->format('F'),
                            'paid_amount'           =>  $amount ?? 0,
                            'discount_amount'       =>  0,
                            'client_id'             =>  $client->id,
                            'user_id'               =>  $user->id,
                            'created_at'            =>  now(),
                            'collected_by'          =>  Employee::onlinePaymentEmployee($type)->id,
                            'payment_method'        =>  'bill_pay',
                            'money_receipt_number'  =>  $type . '_' . $trxid,
                            'expire_date_history'   =>  $client->expire_date,
                            'trx_id'                =>  $trxid,
                            'customerMsisdn'        =>  $mobile,
                            'paymentCreateTime'     =>  Carbon::parse($datetime),
                            'client_id_time'        =>  $client->id . '_' . now()->format('Y-m-d H:i:s')
                        ];

                        $payment = Billpayment::create($data);

                        CustomerAccount::updateCustomrAccount($client->id, (-$amount), $amount, 0);


                        if ($client->pop->reseller->reseller_type == 'own') {

                            $actions = 'Bill Payment. cost ' . $amount . 'TK for the customer ' . $client->userid;

                            $userAccountingId = UserAccounting::create([
                                'received_amount'   => $amount,
                                'paid_amount'       => 0,
                                'actions'           => $actions,
                                'commetns'          => '',
                                'user_id'           => $user->id,
                                'client_id'         => $client->id,
                                'accounting_type'   => $type . ' Bill Pay',
                                'transaction_type'  => $type . ' Bill Pay',
                            ]);
                            $payment->user_accountings_id = $userAccountingId;
                        }


                        $income_type = IncomeHead::find(11);

                        $income =   Income::create([
                            'name' => $income_type->name ?? 'Bill Payment',
                            'date' => now(),
                            'amount' => $amount,
                            'description' => 'Bill Payment from customer : ' . $client->userid,
                            'incomeHead' => 11
                        ]);

                        $payment->income_id = $income->id;
                        $payment->save();

                        $cac = CustomerAccount::where('client_id', $client->id)->first();
                        Log::error("payment id " . $payment->id . " client id " . $client->id);

                        $this->performeExpireDateExtend($client, $payment, $cac, $amount, $client->pop, $current_due_amount, $billpay);


                        $client->save();

                        // Log::error("after commit id ". $payment->id. " client id ". $client->id);
                    }, 1);



                    $payment = Billpayment::where('money_receipt_number', $type . '_' . $trxid)->first();
                    try {
                        // Log::error("Payment id ". $payment->id);
                        if (checkSettings('auto-payment-sms-send') == 'enable') {

                            (new PaymentSms)->billPaymentSms($client, $amount, $trxid, $payment->id);
                        }
                    } catch (\Exception $e) {

                        // Log::error("Sms error " . $client->id . " " . $e->getMessage());

                    }

                    try {
                        if (checkAPI()) {
                            ClientSyncJobForSingle::dispatch($client->id);
                        }
                    } catch (\Throwable $e) {
                        Log::error("Sync error " . $client->id);
                    }

                    Log::error("Return success" . $client->id);

                    return ['status' => 'success', 'message' => 'success'];
                } catch (\Exception $th) {

                    return ['status' => 'duplicate_error', 'message' => $th->getMessage()];
                }
            } else {
                return ['status' => 'trx_id_error', 'message' => 'trx_id_error'];
            }
        }
    }

    public function bkashPaymentProcessReseller($bkash_paymentID, $api)
    {
        if ($api != 'bkashPaymentFromResellerClient') {
            Toastr::error('Something is worng', 'error');
            return redirect()->back();
        }

        $bkash = BkashPayment::where('paymentID', $bkash_paymentID)->where('transactionStatus', 'Completed')->first();
        $client = Client::with('clientsinfo', 'pop', 'packages')->find($bkash->client_id);

        if (checkSettings('ResellerClientOnlineRecharge') == 'enable') {
            if (checkSettings('setClientPaymentAmountToClient') == 'enable' && $client->client_payment_amount > 0) {
                if ($bkash->amount < $client->client_payment_amount) {
                    $client->un_recharge_amount = $bkash->amount;
                    $client->save();

                    Toastr::error('Payment amount is less than the client payment amount', 'error');
                    return redirect()->route('customerDashboard');
                }
            } else {
                if ($bkash->amount < $client->packages->client_payment_amount) {
                    $client->un_recharge_amount = $bkash->amount;
                    $client->save();

                    Toastr::error('Payment amount is less than the client payment amount', 'error');
                    return redirect()->route('customerDashboard');
                }
            }
        }



        DB::beginTransaction();

        try {
            (new CustomerRechargeController)->doCustomerRecharge($client->id, $bkash->paymentID);
            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
        }
    }



    public function bkashPaymentProcess($bkash_paymentID, $api)
    {


        if ($api != 'bkashPaymentFromClient') {
            Toastr::error('Something is worng', 'error');
            return redirect()->back();
        }

        $bkash = BkashPayment::where('paymentID', $bkash_paymentID)->where('transactionStatus', 'Completed')->first();

        $this->billGenerateIfNotExist($bkash->client_id);

        // (new BkashController())->searchTranxection($bkash->trxID);




        $payment = Billpayment::where('money_receipt_number', $bkash->paymentID)->first();

        if ($payment != null) {
            return 'success';
        }

        $client = Client::with('clientsinfo', 'pop', 'pop.reseller', 'customerAccount', 'generatedBill')->withCount('generatedBill')->find($bkash->client_id);


        $current_due_amount = $client->customerAccount->dueAmount ?? 0;


        $bill_payment_check = Billpayment::where('money_receipt_number', $bkash->trxID)->first();

        if (!empty($bkash->amount) && $bkash->transactionStatus == 'Completed' && $bill_payment_check == null) {

            $bkashUser = (new BkashUser)->check();

            $bkashUser = (new AuthUser)->check('user@bkash.com', 'Bkash Online Payment');

            $due_adjust_amount = $bkash->amount;

            $month = now()->month();
            // dd($bill_payment_check);
            DB::transaction(function () use ($bkash, $bkashUser, $current_due_amount, $client) {
                $data = [
                    'description'           =>  'Bkash Bill Payment from client portal Bill Month : ' . today()->format('F'),
                    'paid_amount'           =>  $bkash->amount ?? 0,
                    'discount_amount'       =>  0,
                    'client_id'             =>  $bkash->client_id,
                    'user_id'               =>  User::onlinePaymentUser('Bkash-Online')->id,
                    'created_at'            =>  now(),
                    'collected_by'          =>  Employee::onlinePaymentEmployee('Bkash-Online')->id,
                    'money_receipt_number'  =>  $bkash->trxID,
                    'expire_date_history'   =>  $client->expire_date,
                    'payment_method'        =>  'bkash',
                    'client_id_time'        =>  $bkash->client_id . '_' . now()->format('Y-m-d H:i')
                ];

                $payment = Billpayment::create($data);

                CustomerAccount::updateCustomrAccount($bkash->client_id, (-$bkash->amount), $bkash->amount, 0);

                if ($client->pop->reseller->reseller_type == 'own') {

                    $actions = 'Bill Payment. cost ' . $bkash->amount . 'TK for the customer ' . $client->userid;

                    $userAccountingId = UserAccounting::create([
                        'received_amount'   => $bkash->amount,
                        'paid_amount'       => 0,
                        'actions'           => $actions,
                        'commetns'          => '',
                        'user_id'           => $bkashUser->id,
                        'client_id'         => $bkash->client_id,
                        'accounting_type'   => 'Bkash Payment',
                        'transaction_type'  => 'Bkash Payment',
                    ]);
                    $payment->user_accountings_id = $userAccountingId;
                }

                $income_type = IncomeHead::find(11);

                $income =   Income::create([
                    'name' => $income_type->name ?? 'Bkash Payment',
                    'date' => now(),
                    'amount' => $bkash->amount,
                    'description' => 'Bkash Bill Payment from customer : ' . $client->userid,
                    'incomeHead' => 11
                ]);
                $payment->income_id = $income->id;
                $payment->save();


                $cac = CustomerAccount::where('client_id', $client->id)->first();

                $this->performeExpireDateExtend($client, $payment, $cac, $bkash->amount, $client->pop, $current_due_amount, 'billpay', 0);
            }, 1);



            if (checkSettings('auto-payment-sms-send') == 'enable') {
                try {
                    $bkashDescription = today()->format('F');
                    $payment = Billpayment::where('money_receipt_number', $bkash->trxID)->first();
                    $present_due = $current_due_amount - $bkash->amount;
                    (new PaymentSms)->billPaymentSms($this->getClient($client->id), $bkash->amount, $bkash->trxID, $payment->id, 'bKash', null, $present_due, $bkashDescription);
                    Log::error("Sms error " . $client->id);
                } catch (\Exception $e) {
                    Log::error("Sms error " . $client->id . " " . $e->getMessage());
                }
            }


            if (globalPermission('RadiusExpiration')) {
                try {
                    (new ExpirationService())->handleExpiration($client->userid, $client->expire_date, $client->payment_dadeline, $client->pop->experity_check);
                } catch (\Exception $exce) {
                }
            }
            // dd('ok');

            try {
                if (checkAPI()) {
                    ClientSyncJobForSingle::dispatch($client->id)->delay(now()->addMinutes(5));
                }
            } catch (\Exception $e) {
            }
            Session::flash('success_message', 'Payment is Successful');
        }
    }


    public function performeExpireDateExtend($client, $payment, $cac, $due_adjust_amount, $pop, $current_due_amount, $billpay = '', $discount = 0, $total_day = 30)
    {
        $manuallPayment = $billpay == ""  ? True : false;
        $auto_recharge =  (checkSettings('online_payment_auto_recharge') == 'enable' && $billpay) ? True : False;

        if (getBillingType() == 'day_to_day') {
            $auto_recharge = $billpay ? True : False;
            if (checkSettings('check_manager_balance') == 'enable' && $billpay == '') {
                $billpay = "";
            } else {
                $billpay = 'day_to_day';
            }
        }

        (new CommissionCalculationService())->setCommissionToBillPayment($payment->id);


        $all_pay_bill_auto_payment_to_reseller_sub_reseller = (checkSettings('all_pay_bill_auto_recharge') == 'enable' && $billpay) ? True : False;

        $income = Income::find($payment->income_id);



        if (checkSettings('save_other_to_own_time_client')  && $client->billing_start_date) {
            $start_time = Carbon::parse($client->billing_start_date)->format("Y-m-d H:i:s");
            $end_time = Carbon::parse(now())->format("Y-m-d 23:59:59");

            $reseller_deducted_amount       = ReselleBalanceLogReport::where('client_id', $client->id)
                ->whereBetween('created_at', [$start_time, $end_time])
                ->sum('amount');
            $sub_reseller_deducted_amount   = SubResellerBalanceLogReport::where('client_id', $client->id)
                ->whereBetween('created_at', [$start_time, $end_time])
                ->sum('amount');
        } else {

            $reseller_deducted_amount       = ReselleBalanceLogReport::where('client_id', $client->id)->sum('amount');
            $sub_reseller_deducted_amount   = SubResellerBalanceLogReport::where('client_id', $client->id)->sum('amount');
        }


        if (checkSettings('save_other_to_own_time_client')  && $client->billing_start_date) {
            $total_customer_paid = Billpayment::where('client_id', $client->id)
                ->whereBetween('created_at', [$start_time, $end_time])
                ->sum('paid_amount');

            $reseller_deductable_amount     = $total_customer_paid - $reseller_deducted_amount;
            $sub_reseller_deductable_amount = $total_customer_paid - $sub_reseller_deducted_amount;
        } else {

            $total_customer_paid = ($cac->totalPaid);
            $reseller_deductable_amount     = $total_customer_paid - $reseller_deducted_amount;
            $sub_reseller_deductable_amount = $total_customer_paid - $sub_reseller_deducted_amount;
        }



        if (globalPermission('check_client_balance_before_package_billing_date_change')  && $pop->reseller->reseller_type == 'own') {


            $total_Previous_payment = ($cac->totalPaid + $cac->totalDiscount) - ($payment->paid_amount + $payment->discount_amount);

            $new_customer_bill = BillGenerate::where('client_id', $client->id)
                ->where('billing_type',  'new')
                ->sum('bill_amount');

            if ($total_Previous_payment >= $new_customer_bill) {
                $reseller_deductable_amount = $payment->paid_amount;
                $sub_reseller_deductable_amount = $payment->paid_amount;
            } else {
                $not_deductable_amount = $new_customer_bill - $total_Previous_payment;
                if ($not_deductable_amount >= $payment->paid_amount) {
                    $reseller_deductable_amount = 0;
                    $sub_reseller_deductable_amount = 0;
                } else {
                    $reseller_deductable_amount = $payment->paid_amount - $not_deductable_amount;
                    $sub_reseller_deductable_amount = $payment->paid_amount - $not_deductable_amount;
                }
            }
        }



        if ($reseller_deductable_amount > 0) {

            $curResellerBalance = ExpireCheck::getResellerBalance('reseller', $pop->reseller_id);

            if ($reseller_deductable_amount > $curResellerBalance && $billpay == '') {
                return 'balance_error';
            }

            $resellerBalanceLogId = $this->reseller_balance_deduct($pop, $reseller_deductable_amount, $client, $payment);
        } else {
            Log::error("reseller_balance_deduct " . $reseller_deductable_amount);
            $resellerBalanceLogId = $this->reseller_balance_deduct($pop, 0, $client, $payment);
        }

        // dd($sub_reseller_deductable_amount);

      if ($pop->subreseller == 'yes'){

          if ($sub_reseller_deductable_amount > 0) {

              if ($pop->subreseller == 'yes') {

                  $cur_sub_reseller_balance = ExpireCheck::getResellerBalance('pop', $pop->id);

                  if ($sub_reseller_deductable_amount > $cur_sub_reseller_balance && $billpay == '') {
                      return 'balance_error';
                  }

                  $this->sub_reseller_balance_deduct($pop, $sub_reseller_deductable_amount, $client, $payment, $reseller_deductable_amount, $resellerBalanceLogId);
              }
          } else {
              $this->sub_reseller_balance_deduct($pop, 0, $client, $payment, $reseller_deductable_amount, $resellerBalanceLogId);
          }
      }



        if ($all_pay_bill_auto_payment_to_reseller_sub_reseller && !$manuallPayment) {

            $payment = Billpayment::find($payment->id);

            if ($payment) {
                $gateway_transaction_id = $payment->trx_id;

                // Count occurrences of trx_id
                $check_balance_log_by_trx_id = ResellerRechargeReport::whereNotNull('payment_gateway_transaction_id')
                    ->where('payment_gateway_transaction_id', $gateway_transaction_id)
                    ->count();

                // Count occurrences of money_receipt_number
                $check_balance_log_by_money_recipt = ResellerRechargeReport::whereNotNull('payment_gateway_transaction_id')
                    ->where('payment_gateway_transaction_id', $payment->money_receipt_number)
                    ->count();

                // Determine if balance can be added
                $add_balance = $check_balance_log_by_trx_id <= 0 && $check_balance_log_by_money_recipt <= 0;


                if ($add_balance) {

                    $remark = 'Recharge By Online Payment. Customer ' . $client->userid . ' CID: ' . $client->id;

                    if ($pop->subreseller == 'yes') {
                        (new ResellerRechargeController)->rechargeByOnlinePayment($pop->reseller_id, $payment->paid_amount, $client, $billpay);
                        (new PopController)->rechargeByOnlinePayment('pop', $pop->id, $payment->paid_amount, $remark, $payment->paid_amount, 1);
                    } else {
                        (new ResellerRechargeController)->rechargeByOnlinePayment($pop->reseller_id, $payment->paid_amount, $client, $billpay);
                    }
                }
            }
        }



        $exp = Carbon::parse($client->expire_date);

        $month_dif = 0;
        $dif = $exp->diffInMonths(today());
        $cac = CustomerAccount::where('client_id', $client->id)->first();

        $dueAmount = $cac->dueAmount;
        $otcDue = abs($client->clientsinfo->otc_due);
        $totalDue = $dueAmount - $otcDue;



        if ($cac->dueAmount <= 0 && ($cac->dueAmount - abs($client->clientsinfo->otc_due)) <= 0) {
            Log::error("extendt deate triger");
            $this->onPaymentUpdateInfo($client, $exp, $month_dif, $payment->id, $total_day);
        } else {
            Log::error("not extend date trigger for payment {$payment->id}");
            Log::error("due amount: {$dueAmount}, otc due: {$otcDue}, remaining: {$totalDue}");
        }
    }


    public function uddoktapay($request, $UddoktaPayLog = null)
    {

        $gateway = 'Uddokta-Pay';

        $info = array(
            'customer_id'    => $request['metadata']['customer_id'],
            'amount'         => $request['amount'],
            'transaction_id' => $request['transaction_id'],
            'description'    => 'Online Bill Payment By: ' . $gateway . ' Method: ' . $request['payment_method'],
            'payment_method' => $request['payment_method'],
        );

        if ($info['customer_id'] == null) {
            return response()->json(['status' => 'error', 'message' => 'Customer ID not found']);
        }


        $this->billGenerateIfNotExist($request['metadata']['customer_id']);

        $client = Client::with('clientsinfo', 'pop', 'pop.reseller', 'customerAccount', 'generatedBill')->withCount('generatedBill')->find($info['customer_id']);
        if (!$client) {
            return response()->json(['status' => 'error', 'message' => 'Customer not found']);
        }

        $billPayment = Billpayment::where('money_receipt_number', 'UD_' . $info['transaction_id'])->first();
        if ($billPayment) {
            return response()->json(['status' => 'error', 'message' => 'Transaction already exist']);
        }

        $payment = Billpayment::create([
            'description'           =>  $info['description'],
            'paid_amount'           =>  $info['amount'] ?? 0,
            'discount_amount'       =>  0,
            'client_id'             =>  $info['customer_id'],
            'user_id'               =>  User::onlinePaymentUser($gateway)->id,
            'created_at'            =>  now(),
            'collected_by'          =>  Employee::onlinePaymentEmployee($gateway)->id,
            'money_receipt_number'  =>  'UP_' . $info['transaction_id'],
            'trx_id'                =>  $info['transaction_id'],
            'payment_method'        =>  'Online Payment ' . $info['payment_method'],
            'client_id_time'        =>  $info['customer_id'] . '_' . now()->format('Y-m-d H:i')
        ]);

        $income =   Income::create([
            'name' => 'Online Payment by ' . $gateway,
            'date' => now(),
            'amount' => $info['amount'] ?? 0,
            'description' => 'Online Bill Payment (' . $gateway . ')  for customer : ' . $client->userid,
            'incomeHead' => 11
        ]);
        $payment->income_id = $income->id;
        $payment->save();

        CustomerAccount::updateCustomrAccount($info['customer_id'], (-$info['amount']), $info['amount'], 0);
        $cac = CustomerAccount::where('client_id', $client->id)->first();



        $current_due_amount = $client->customerAccount->dueAmount ?? 0;


        $status =  $this->performeExpireDateExtend($client, $payment, $cac, $info['amount'], $client->pop, $current_due_amount, 'billpay', 0);

        if (checkAPI()) {
            ClientSyncJobForSingle::dispatch($client->id);
        }


        if ($status == 'balance_error') {
            return 'error';
        } else {
            if (checkSettings('auto-payment-sms-send') == 'enable') {
                $present_due = $current_due_amount - $info['amount'];
                (new PaymentSms)->billPaymentSms($client, $info['amount'], $info['transaction_id'], $payment->id, 'uddoktapay', null, $present_due);
            }

            // check if payment email will be send
            $emailSetting = json_decode(emailSetting()->where('tamplate_name', 'customer_payment_eamil')->first()->email_body);
            if ($emailSetting->sendemail == 'Yes') {
                SendPaymentMailJob::dispatch($client, $payment, $emailSetting);
            }

            $info = array(
                'id' => $request['metadata']['customer_id'],
                'login_status' => 'success'
            );

            Session::put('customer_info', json_encode($info));
            // return response()->json(['status' => 'success', 'message' => 'Payment Completed Successfully']);

            //return success response message

            if ($UddoktaPayLog) {
                $UddoktaPayLog->status = 'done';
                $UddoktaPayLog->save();
            }
            return response()->json(['status' => 'success', 'message' => 'Payment Completed Successfully']);
        }



        // return redirect()->route('customerDashboard')->with('success_message', 'Payment Completed Successfully');
    }



    public function sslpayment(Request $request)
    {
        if ($request->gateway && $request->gateway == 'uddoktapay') {
            $gateway = 'Uddokta-Pay';
        } else {
            $gateway = 'SSL-Commerz';
        }

        $info = array(
            'customer_id'    => $request->value_a,
            'amount'         => $request->amount,
            'transaction_id' => $request->tran_id,
            'description'    => 'Online Bill Payment: ' . $gateway . ' Bill Month : ' . today()->format('F'),
        );

        $this->billGenerateIfNotExist($request->value_a);


        // $client = ClientServices::customerinfo($info['customer_id'])->first();

        $client = Client::with('clientsinfo', 'pop', 'pop.reseller', 'customerAccount', 'generatedBill')->withCount('generatedBill')->find($info['customer_id']);


        $payment = Billpayment::create([
            'description'           =>  $info['description'],
            'paid_amount'           =>  $info['amount'] ?? 0,
            'discount_amount'       =>  0,
            'client_id'             =>  $info['customer_id'],
            'user_id'               =>  User::onlinePaymentUser($gateway)->id,
            'created_at'            =>  now(),
            'collected_by'          =>  Employee::onlinePaymentEmployee($gateway)->id,
            'money_receipt_number'  =>  'SSL_' . $info['transaction_id'],
            'trx_id'                =>  $info['transaction_id'],
            'payment_method'        =>  'Online Payment',
            'client_id_time'        =>  $info['customer_id'] . '_' . now()->format('Y-m-d H:i')
        ]);

        $income =   Income::create([
            'name' => 'Online Payment by ' . $gateway,
            'date' => now(),
            'amount' => $info['amount'] ?? 0,
            'description' => 'Online Bill Payment (' . $gateway . ')  for customer : ' . $client->userid,
            'incomeHead' => 11
        ]);
        $payment->income_id = $income->id;
        $payment->save();

        CustomerAccount::updateCustomrAccount($info['customer_id'], (-$info['amount']), $info['amount'], 0);
        $cac = CustomerAccount::where('client_id', $client->id)->first();



        $current_due_amount = $client->customerAccount->dueAmount ?? 0;


        // $this->performeExpireDateExtendForOnlinePayment($client, $info, $payment, $cac);

        $status =  $this->performeExpireDateExtend($client, $payment, $cac, $info['amount'], $client->pop, $current_due_amount, 'billpay', 0);

        if (checkAPI()) {
            ClientSyncJobForSingle::dispatch($client->id);
        }


        if ($status == 'balance_error') {
            return 'error';
        } else {
            if (checkSettings('auto-payment-sms-send') == 'enable') {
                try {
                    $present_due = $current_due_amount - $info['amount'];
                    (new PaymentSms)->billPaymentSms($client, $info['amount'], $info['transaction_id'], $payment->id, 'sslpayment', null, $present_due);
                } catch (\Exception $e) {
                }
            }

            // check if payment email will be send
            $emailSetting = json_decode(emailSetting()->where('tamplate_name', 'customer_payment_eamil')->first()->email_body);
            if ($emailSetting->sendemail == 'Yes') {
                try {
                    SendPaymentMailJob::dispatch($client, $payment, $emailSetting);
                } catch (\Exception $e) {
                }
            }

            $info = array(
                'id' => $request->value_a,
                'login_status' => 'success'
            );

            $request->session()->put('customer_info', json_encode($info));

            return 'success';
        }



        // return redirect()->route('customerDashboard')->with('success_message', 'Payment Completed Successfully');
    }


    public function performeExpireDateExtendForOnlinePayment($client, $info, $payment, $cac)
    {
        $pop = Pop::find($client->pop_id);
        $reseller_deducted_amount = ReselleBalanceLogReport::where('client_id', $client->id)->sum('amount');
        $sub_reseller_deducted_amount = SubResellerBalanceLogReport::where('client_id', $client->id)->sum('amount');

        $total_customer_paid = ($cac->totalPaid + $cac->totalDiscount);

        $reseller_deductable_amount = round($total_customer_paid - $reseller_deducted_amount, 2);
        $sub_reseller_deductable_amount = round($total_customer_paid - $sub_reseller_deducted_amount, 2);


        $resellerBalanceLogId = $this->reseller_balance_deduct($pop, $reseller_deductable_amount, $client, $payment);


        if ($pop->subreseller == 'yes') {
            $this->sub_reseller_balance_deduct($pop, $sub_reseller_deductable_amount, $client, $payment, $reseller_deductable_amount, $resellerBalanceLogId);
        }

        if ($client->clients_status == 'expired' && $client->expire_date <= now()) {

            if ($cac->dueAmount < 0 && abs($cac->dueAmount) >= $client->package_rate) {

                $exp = Carbon::parse($client->expire_date);
                if ($exp->diffInMonths(now()) < 1) {

                    $this->onPaymentUpdateInfo($client, $exp, 1, $payment->id);
                } else {
                    $exp = Carbon::parse(date('Y-m-' . $client->billing_cycle));
                    $this->onPaymentUpdateInfo($client, $exp, 1, $payment->id);
                }
            }
        }
    }


    public function reseller_balance_deduct($pop, $reseller_deductable_amount, $client, $payment)
    {

        if (isset(auth()->user()->email)) {
            $created_by = auth()->user()->email;
        } else {
            $created_by = 'Online Payment';
        }


        Balance::balanceDeductForUserRecharge('reseller', $pop->reseller_id, $reseller_deductable_amount);

        if ($client->packages->commission > 0 || globalPermission('commission_from_manager_pop')) {

            (new CommissionService())->reseller_commission($reseller_deductable_amount, 'payment', $pop->reseller_id, $client->packages->commission, $client->packages->package_rate, $client->id, "payment", $payment->id);
        }
        $reseller = Reseller::find($pop->reseller_id);
        $report = ReselleBalanceLogReport::create(
            [
                'reseller_id' => $pop->reseller_id,
                'client_id'   => $client->id,
                'action'      => 'Bill payment from payment option payment id: ' . $payment->id,
                'amount'      => $reseller_deductable_amount,
                'remarks'     => 'Created BY ' . $created_by,
                'uniqueId'    => createUUID(),
                'pop_id'      => $client->pop_id,
                'commission_amount' => getCommissionForResellerRecharge($client->id, $reseller_deductable_amount),
                'reseller_commission_percentage' => $reseller->commission_percentage,
                'pop_commission_percentage' => $pop->commission_percentage,
            ]
        );

        $payment->reseller_balance_deduct = $reseller_deductable_amount;
        $payment->reseller_balance_log_report = $report->id;
        $payment->save();

        return $report->id;
    }


    public function sub_reseller_balance_deduct($pop, $sub_reseller_deducted_amount, $client, $payment, $resellerDeductAmount = 0, $resellerBalanceLogId = null)
    {
        $created_by = auth()->user() ? auth()->user()->email : 'Online Payment';
        Balance::balanceDeductForUserRecharge('pop', $pop->id, $sub_reseller_deducted_amount);
        if ($client->subpack->commission > 0 || globalPermission('commission_from_manager_pop')) {

            (new CommissionService())->subreseller_commission($sub_reseller_deducted_amount, 'payment', $pop->id, $client->subpack->commission, $client->subpack->rate, $client->id, "payment", $payment->id);
        }
        $report = SubResellerBalanceLogReport::create(
            [
                'reseller_id'       => $pop->reseller_id,
                'client_id'         => $client->id,
                'action'            => 'Bill payment from payment option payment id: ' . $payment->payment_id,
                'amount'            => $sub_reseller_deducted_amount,
                'sub_reseller_id'   => $pop->id,
                'remarks'           => 'Created BY ' . $created_by,
                'reseller_cost' => $resellerDeductAmount,
                'commission_amount' => getCommissionForSubResellerRecharge($client->id, $sub_reseller_deducted_amount,),
                'reseller_balance_log_id' => $resellerBalanceLogId,
            ]
        );

        $payment->pop_balance_deduct = $sub_reseller_deducted_amount;
        $payment->sub_reseller_balance_log_report = $report->id;
        $payment->save();
    }

    public function resellerBalanceDeductCheck($pop, $extra_balance, $client, $cac, $payment)
    {
        if ($pop->billable == 'yes') {

            $curResellerBalance = ExpireCheck::getResellerBalance('reseller', $pop->reseller_id);

            if ($extra_balance > $curResellerBalance) {
                return redirect()->back()->with('error_message', 'Not Enough Balance');
            }

            Balance::deductBalanceOnPaymentFromReseller($client->id, $pop->reseller_id, $extra_balance, $cac, $payment->id, $pop_id);
        }
    }




    public function onPaymentUpdateInfo($client, $expdate, $month, $payment_id, $total_day = 30)
    {

        $current_month_billing_date = Carbon::parse(date($client->billing_cycle . '-M-Y'));

        if (globalPermission('round_expire_date')) {
            if (Carbon::parse($client->expire_date) < today() && globalPermission('extendFromToDayOwnCustomer')) {
                $current_month_billing_date = (new ExpireDateRoundService())->currentMonthExpireDate(date('d'));
            } else {
                $current_month_billing_date = (new ExpireDateRoundService())->currentMonthExpireDate($client->billing_cycle);
            }
        }

        $bill = BillGenerate::where('client_id', $client->id)
            ->whereBetween('created_at', [today()->firstOfMonth(), today()->endOfMonth()])
            ->where('billing_type', 'monthly')
            ->first();

        $date = $client->expire_date;


        if ($bill) {

            if (Carbon::parse($client->expire_date) < today()->endOfMonth()) {
                $date = Carbon::parse($current_month_billing_date)->addMonth();
                if (globalPermission('round_expire_date')) {
                    $date = (new ExpireDateRoundService())->roundDate($current_month_billing_date);
                }
            } else {
                if ($client->expire_date < $current_month_billing_date) {

                    $date = Carbon::parse($current_month_billing_date);
                } else {
                    $date = Carbon::parse($client->expire_date);
                }
                // dd($date,$current_month_billing_date);
            }
        } else {


            $newcheck = BillGenerate::where('client_id', $client->id)
                ->whereBetween('created_at', [today()->firstOfMonth(), today()->endOfMonth()])
                ->whereIn('billing_type', ['new', 'otc'])
                ->first();

            if ($newcheck) {
                $date = Carbon::parse($client->expire_date);
            } else {
                if (Carbon::parse($client->expire_date) < today()->endOfMonth()) {
                    $date = Carbon::parse($client->expire_date)->addMonth();
                    if (globalPermission('round_expire_date')) {
                        $date = (new ExpireDateRoundService())->roundDate($client->expire_date);
                    }
                }
            }
        }

        if (getBillingType() === 'day_to_day') {

            $customerAccount = CustomerAccount::where('client_id', $client->id)->first();
            $client_package = Packages::find($client->package_id);
            $addvanced_balance = abs($customerAccount->dueAmount);

            if (Carbon::parse($client->expire_date) < today() && $addvanced_balance >= ($client_package->package_rate - $client->parmanent_discount)) {

                (new SecondMonthlyBillGenerateForDayToDay)->generate(
                    $client->id,
                    "monthly",
                    $client_package->package_rate,
                    'Monthly Bill Generate ',
                    $client->parmanent_discount,
                    $client_package->client_package,
                    $client_package->package_rate,
                    $client->expire_date
                );


                $customerAccount->dueAmount =  $customerAccount->dueAmount + ($client_package->package_rate - $client->parmanent_discount);
                $customerAccount->save();
                if (checkSettings('d2d_extend_ExpireDate_By_Month') == 'enable') {
                    $total_day_of_this_month = now()->lastOfMonth()->format('d');

                    if (globalPermission('countPaymentDateAsOneDayForExpireDate')) {
                        $total_day_of_this_month = $total_day_of_this_month - 1;
                    }

                    $date = Carbon::parse(today())->addDay($total_day_of_this_month);

                    if (globalPermission('round_expire_date_after_d2d_extend_ExpireDate_By_Month')) {
                        $date = (new ExpireDateRoundService())->roundExpireDateForRecharge(today(), $date);
                    }
                } else {
                    $date = Carbon::parse(today())->addDay(29);
                }

                if (globalPermission('round_expire_date')) {
                    $date = (new ExpireDateRoundService())->roundDate(today());
                }
            } else {

                Log::error(
                    "onPaymentUpdateInfo | Passed Condition: " .
                        ((Carbon::parse($client->expire_date) < today() &&
                            $addvanced_balance >= ($client_package->package_rate - $client->parmanent_discount)) ? 'true' : 'false') .
                        " | Date result: " .
                        ((Carbon::parse($client->expire_date) < today()) ? 'true' : 'false') .
                        " | Client Balance Result: " .
                        (($addvanced_balance >= ($client_package->package_rate - $client->parmanent_discount)) ? 'true' : 'false') .
                        " | Customer Balance: " . $addvanced_balance .
                        " | Customer Bill: " . ($client_package->package_rate - $client->parmanent_discount) .
                        " | Customer package rate: " . ($client_package->package_rate) .
                        " | Customer package id: " . ($client_package->id) .
                        " | Customer parmanent_discount: " . ($client->parmanent_discount) .
                        " | Expire Date: " . $client->expire_date .
                        " | Today: " . today()
                );


                $date = Carbon::parse($client->expire_date);
            }
        }





        $client = Client::with('pop')->withTrashed()->find($client->id);
        $old_expire_date = $client->expire_date;

        $client->expire_date    = $date;
        $client->billing_cycle = Carbon::parse($date)->format('d');

        $client->payment_dadeline   = 0;
        $client->save();

        if ($client->expire_date >= today()) {
            $client->clients_status = 'active';
            $client->save();
        }

        if (!checkAPI()) {
            (new RadiusClientSync)->syncSingleRadiusClient($client->id);
        }
    }


    public function paymentDelete(Request $request)
    {

        $payment = Billpayment::with('user', 'income')->find($request->payment_id);
        $amount = floatval($payment->paid_amount) + floatval($payment->discount_amount);
        $paid_amount = floatval($payment->paid_amount);

        if ($payment->paid_amount == 0 && $payment->discount_amount == 0) {
            return redirect()->back()->with('success_message', 'Payment and discount both amount are 0 so no need to delete.');
        }
        // dd($payment);
        if (globalPermission('payment-bill-by-bill')) {
            if ($payment->bill_ids == null) {
                return redirect()->back()->with('error_message', 'Payment can not be deleted.');
            }
        }

        DB::beginTransaction();

        try {

            if (globalPermission('payment-bill-by-bill')) {
                $bill_ids = $payment->bill_ids;
                $total_paid_amount = $payment->paid_amount + $payment->discount_amount;
                $bill = BillGenerate::find($bill_ids);

                $previous_paid_amount = $bill->paid_amount;
                $bill->paid_amount = $previous_paid_amount - $total_paid_amount;
                $bill->save();
            }

            $reseller_commission = ResellerCommissionReference::where('bill_payment_id', $payment->id)->first();
            if ($reseller_commission && $reseller_commission->bill_payment_id != null) {
                $reseller_commission->actions = $reseller_commission->actions . " deleted";
                $reseller_commission->received_amount = 0;
                $reseller_commission->save();
            }

            $sub_manager_commission_log = SubResellerCommissionReference::where('payment_id', $payment->id)->first();

            if ($sub_manager_commission_log && $sub_manager_commission_log->payment_id != null) {
                $sub_manager_commission_log->actions = $sub_manager_commission_log->actions . " deleted";
                $sub_manager_commission_log->received_amount = 0;
                $sub_manager_commission_log->save();
            }


            $clientIdForThisBillDelete = PaymentDeleteController::deletePayment($payment, $amount, $paid_amount);

            if (checkSettings('otc_payment_with_generale_payment') == 'enable') {

                $checkOtcPayment = OtcPaymentLog::where('payment_id', $payment->id)->get();
                if (count($checkOtcPayment) > 0) {
                    $clientInfo = Clientsinfo::where('client_id', $payment->client_id)->first();
                    $clientInfo->otc_due = $clientInfo->otc;
                    $clientInfo->save();
                    OtcPaymentLog::where('client_id', $payment->client_id)->delete();
                }
            }


            DB::commit();

            if (!globalPermission('payment-bill-by-bill')) {
                BillGenerateUpdateJob::dispatch($payment->client_id);
            }


            return redirect()->back()->with('success_message', 'Payment Successfully Reverted.');
        } catch (\Throwable $th) {

            DB::rollBack();
            return redirect()->back()->with('success_message', 'Payment Deleted Unsuccessfull.');
        }
    }

    public function dueHistoryInPayment($id)
    {
        $due_months = BillGenerate::where('client_id', $id)
            ->whereColumn('bill_amount', '!=', 'paid_amount')
            ->get();

        $months = [];

        foreach ($due_months as $due_month) {
            $date = Carbon::parse($due_month->created_at)->format('M');
            $amount = $due_month->bill_amount - $due_month->paid_amount;
            // $months[] = "<button class='btn btn-secondary mx-2 btn-sm' disabled type='button'>". $date ."</button>";
            $months[] = "<tr>
                        <td width='70%'>" . $date . "</td>
                        <td width='30%'>" . $amount . "tk</td>
                        </tr>";
        }

        return $months;
    }

    public function invoicePrint($id)
    {
        $billpayment = Billpayment::with('clients', 'clients.packages', 'clientsinfo', 'employee', 'clients.customerAccount')->find($id);

        $data = [
            'billpayment'  => $billpayment,
            'company_info' => CompanyInformation::latest()->first(),
        ];
        // dd($data);
        return view('billing.printInvoice', $data);
    }

    public function UpaypaymentProcess($amount, $client_id, $trx_id)
    {

        $this->billGenerateIfNotExist($client_id);

        $client = Client::with('clientsinfo', 'pop', 'pop.reseller', 'customerAccount', 'generatedBill')->withCount('generatedBill')->find($client_id);
        $current_due_amount = $client->customerAccount->dueAmount ?? 0;
        // dd($client_id);
        if (!empty($amount)) {

            DB::transaction(function () use ($client_id, $trx_id, $current_due_amount, $amount, $client) {
                $data = [
                    'description'           =>  'Upay Bill Payment from client portal',
                    'paid_amount'           =>  $amount ?? 0,
                    'discount_amount'       =>  0,
                    'client_id'             =>  $client_id,
                    'user_id'               =>  User::onlinePaymentUser('Upay-Online')->id,
                    'created_at'            =>  now(),
                    'collected_by'          =>  Employee::onlinePaymentEmployee('Upay-Online')->id,
                    'money_receipt_number'  =>  $trx_id,
                    'expire_date_history'   =>  $client->expire_date,
                    'payment_method'        =>  'upay',
                    'client_id_time'        =>  $client_id . '_' . now()->format('Y-m-d H:i')
                ];
                $payment = Billpayment::create($data);

                CustomerAccount::updateCustomrAccount($client_id, (-$amount), $amount, 0);

                if ($client->pop->reseller->reseller_type == 'own') {

                    $actions = 'Bill Payment. cost ' . $amount . 'TK for the customer ' . $client->userid;

                    $userAccountingId = UserAccounting::create([
                        'received_amount'   => $amount,
                        'paid_amount'       => 0,
                        'actions'           => $actions,
                        'commetns'          => '',
                        'user_id'           => User::onlinePaymentUser('Upay-Online')->id,
                        'client_id'         => $client_id,
                        'accounting_type'   => 'Upay Payment',
                        'transaction_type'  => 'Upay Payment',
                    ]);
                    $payment->user_accountings_id = $userAccountingId;
                }

                $income_type = IncomeHead::find(11);

                $income =   Income::create([
                    'name' => $income_type->name ?? 'Upay Payment',
                    'date' => now(),
                    'amount' => $amount,
                    'description' => 'Upay Bill Payment from customer : ' . $client->userid,
                    'incomeHead' => 11
                ]);
                $payment->income_id = $income->id;
                $payment->save();


                $cac = CustomerAccount::where('client_id', $client->id)->first();

                $this->performeExpireDateExtend($client, $payment, $cac, $amount, $client->pop, $current_due_amount, 'billpay', 0);
            }, 1);


            if (checkSettings('auto-payment-sms-send') == 'enable') {
                try {
                    $payment = Billpayment::where('money_receipt_number', $trx_id)->first();
                    $present_due = $current_due_amount - $amount;
                    (new PaymentSms)->billPaymentSms($client, $amount, $trx_id, $payment->id, 'upay', null, $present_due);
                } catch (\Exception $e) {
                }
            }

            if (globalPermission('RadiusExpiration')) {
                try {
                    (new ExpirationService())->handleExpiration($client->userid, $client->expire_date, $client->payment_dadeline, $client->pop->experity_check);
                } catch (\Exception $exce) {
                }
            }


            Session::flash('success_message', 'Upay Payment is Successful');
        }
    }

    public function NagadClientCheckOutPaymentProcess($amount, $client_id, $trx_id, $mobile_that_use, $payment_ref_id, $payment_created_time)
    {
        DB::beginTransaction();
        try {
            $this->billGenerateIfNotExist($client_id);

            $client = Client::with('clientsinfo', 'pop', 'pop.reseller', 'customerAccount', 'generatedBill')->withCount('generatedBill')->find($client_id);
            $current_due_amount = $client->customerAccount->dueAmount ?? 0;
            // dd($client_id);
            if (!empty($amount)) {

                $data = [
                    'description'           =>  'Nagad Bill Payment from client portal',
                    'paid_amount'           =>  $amount ?? 0,
                    'discount_amount'       =>  0,
                    'client_id'             =>  $client_id,
                    'user_id'               =>  User::onlinePaymentUser('Nagad-Online')->id,
                    'created_at'            =>  now(),
                    'collected_by'          =>  Employee::onlinePaymentEmployee('Nagad-Online')->id,
                    'money_receipt_number'  =>  $trx_id,
                    'expire_date_history'   =>  $client->expire_date,
                    'payment_method'        =>  'nagad',
                    'client_id_time'        =>  $client_id . '_' . now()->format('Y-m-d H:i'),
                    'trx_id'                =>  $payment_ref_id,
                    'customerMsisdn'       =>  $mobile_that_use,
                    'paymentCreateTime'    =>  $payment_created_time,
                ];
                $payment = Billpayment::create($data);

                CustomerAccount::updateCustomrAccount($client_id, (-$amount), $amount, 0);

                if ($client->pop->reseller->reseller_type == 'own') {

                    $actions = 'Bill Payment. cost ' . $amount . 'TK for the customer ' . $client->userid;

                    $userAccountingId = UserAccounting::create([
                        'received_amount'   => $amount,
                        'paid_amount'       => 0,
                        'actions'           => $actions,
                        'commetns'          => '',
                        'user_id'           => User::onlinePaymentUser('Nagad-Online')->id,
                        'client_id'         => $client_id,
                        'accounting_type'   => 'Nagad Payment',
                        'transaction_type'  => 'Nagad Payment',
                    ]);
                    $payment->user_accountings_id = $userAccountingId;
                }

                $income_type = IncomeHead::find(11);

                $income =   Income::create([
                    'name' => $income_type->name ?? 'Nagad Payment',
                    'date' => now(),
                    'amount' => $amount,
                    'description' => 'Nagad Bill Payment from customer : ' . $client->userid,
                    'incomeHead' => 11
                ]);
                $payment->income_id = $income->id;
                $payment->save();


                $cac = CustomerAccount::where('client_id', $client->id)->first();

                $this->performeExpireDateExtend($client, $payment, $cac, $amount, $client->pop, $current_due_amount, 'billpay', 0);

                DB::commit();


                if (checkSettings('auto-payment-sms-send') == 'enable') {
                    try {
                        $present_due = $current_due_amount - $amount;
                        (new PaymentSms)->billPaymentSms($client, $amount, $trx_id, $payment->id, 'nagad', null, $present_due);
                    } catch (\Exception $e) {
                    }
                }

                if (globalPermission('RadiusExpiration')) {
                    try {
                        (new ExpirationService())->handleExpiration($client->userid, $client->expire_date, $client->payment_dadeline, $client->pop->experity_check);
                    } catch (\Exception $exce) {
                    }
                }

                Session::flash('success_message', 'Nagad Payment is Successful');
            }
        } catch (Exception $ex) {
        }
    }

    public function surjoPayClientCheckOutPaymentProcess($amount, $client_id, $trx_id, $phone_no, $invoice_no, $date_time)
    {
        $this->billGenerateIfNotExist($client_id);

        $client = Client::with('clientsinfo', 'pop', 'pop.reseller', 'customerAccount', 'generatedBill')->withCount('generatedBill')->find($client_id);
        $current_due_amount = $client->customerAccount->dueAmount ?? 0;
        // dd($amount);

        if (!empty($amount)) {

            $data = [
                'description'           =>  'Surjo Pay Bill Payment from client portal',
                'paid_amount'           =>  $amount ?? 0,
                'discount_amount'       =>  0,
                'client_id'             =>  $client_id,
                'user_id'               =>  User::onlinePaymentUser('Surjopay-Online')->id,
                'created_at'            =>  now(),
                'collected_by'          =>  Employee::onlinePaymentEmployee('Surjopay-Online')->id,
                'money_receipt_number'  =>  $invoice_no,
                'expire_date_history'   =>  $client->expire_date,
                'payment_method'        =>  'Surjopay',
                'client_id_time'        =>  $client_id . '_' . now()->format('Y-m-d H:i'),
                'trx_id'                =>  $trx_id,
                'customerMsisdn'       =>  $phone_no,
                'paymentCreateTime'    =>  $date_time,
            ];
            $payment = Billpayment::create($data);

            CustomerAccount::updateCustomrAccount($client_id, (-$amount), $amount, 0,);

            if ($client->pop->reseller->reseller_type == 'own') {

                $actions = 'Bill Payment. cost ' . $amount . 'TK for the customer ' . $client->userid;

                $userAccountingId = UserAccounting::create([
                    'received_amount'   => $amount,
                    'paid_amount'       => 0,
                    'actions'           => $actions,
                    'commetns'          => '',
                    'user_id'           => User::onlinePaymentUser('Surjopay-Online')->id,
                    'client_id'         => $client_id,
                    'accounting_type'   => 'Surjopay Payment',
                    'transaction_type'  => 'Surjopay Payment',
                ]);
                $payment->user_accountings_id = $userAccountingId;
            }

            $income_type = IncomeHead::find(11);

            $income =   Income::create([
                'name' => $income_type->name ?? 'Surjopay Payment',
                'date' => now(),
                'amount' => $amount,
                'description' => 'Surjopay Bill Payment from customer : ' . $client->userid,
                'incomeHead' => 11
            ]);
            $payment->income_id = $income->id;
            $payment->save();


            $cac = CustomerAccount::where('client_id', $client->id)->first();

            $this->performeExpireDateExtend($client, $payment, $cac, $amount, $client->pop, $current_due_amount, 'billpay', 0);

            if (checkSettings('auto-payment-sms-send') == 'enable') {
                try {
                    $present_due = $current_due_amount - $amount;
                    (new PaymentSms)->billPaymentSms($client, $amount, $trx_id, $payment->id, 'Surjopay', null, $present_due);
                } catch (\Exception $e) {
                }
            }

            Session::flash('success_message', 'Surjopay Payment is Successful');
        }
    }

    public function bkashWebhookPaymentProcess($amount, $client_id, $trx_id, $phone_no, $invoice_no, $date_time)
    {
        $this->billGenerateIfNotExist($client_id);

        $client = Client::with('clientsinfo', 'pop', 'pop.reseller', 'customerAccount', 'generatedBill')->withCount('generatedBill')->find($client_id);
        $current_due_amount = $client->customerAccount->dueAmount ?? 0;
        // dd($amount);

        if (!empty($amount)) {

            $data = [
                'description'           =>  'Bill Payment by Bkash Webhook',
                'paid_amount'           =>  $amount ?? 0,
                'discount_amount'       =>  0,
                'client_id'             =>  $client_id,
                'user_id'               =>  User::onlinePaymentUser('Bkash-Webhook')->id,
                'created_at'            =>  now(),
                'collected_by'          =>  Employee::onlinePaymentEmployee('Bkash-Webhook')->id,
                'money_receipt_number'  =>  $invoice_no,
                'expire_date_history'   =>  $client->expire_date,
                'payment_method'        =>  'Bkash Webhook',
                'client_id_time'        =>  $client_id . '_' . now()->format('Y-m-d H:i'),
                'trx_id'                =>  $trx_id,
                'customerMsisdn'       =>  $phone_no,
                'paymentCreateTime'    =>  $date_time,
            ];
            $payment = Billpayment::create($data);

            CustomerAccount::updateCustomrAccount($client_id, (-$amount), $amount, 0,);

            if ($client->pop->reseller->reseller_type == 'own') {

                $actions = 'Bill Payment. cost ' . $amount . 'TK for the customer ' . $client->userid;

                $userAccountingId = UserAccounting::create([
                    'received_amount'   => $amount,
                    'paid_amount'       => 0,
                    'actions'           => $actions,
                    'commetns'          => '',
                    'user_id'           => User::onlinePaymentUser('Bkash-Webhook')->id,
                    'client_id'         => $client_id,
                    'accounting_type'   => 'Bkash-Webhook',
                    'transaction_type'  => 'Bkash-Webhook',
                ]);
                $payment->user_accountings_id = $userAccountingId;
            }

            $income_type = IncomeHead::find(11);

            $income =   Income::create([
                'name' => $income_type->name ?? 'Bkash-Webhook',
                'date' => now(),
                'amount' => $amount,
                'description' => 'Bkash-Webhook Bill Payment from customer : ' . $client->userid,
                'incomeHead' => 11
            ]);
            $payment->income_id = $income->id;
            $payment->save();


            $cac = CustomerAccount::where('client_id', $client->id)->first();

            $this->performeExpireDateExtend($client, $payment, $cac, $amount, $client->pop, $current_due_amount, 'Webhook', 0);

            if (checkSettings('auto-payment-sms-send') == 'enable') {
                try {
                    $present_due = $current_due_amount - $amount;
                    (new PaymentSms)->billPaymentSms($client, $amount, $trx_id, $payment->id, 'Bkash-Webhook', null, $present_due);
                } catch (\Exception $e) {
                }
            }

            Session::flash('success_message', 'Bkash-Webhook Payment is Successful');
        }
    }
}
