<?php

namespace App\Http\Controllers;

use App\Cart;
use App\Mail\GenericMail;
use App\Model\Client\SmtpSetting;
use App\Model\Client\UserPackage;
use App\Model\Client\wallet;
use App\Model\Client\walletTransaction;
use App\Model\Master\ClientPackage;
use App\Model\Master\Order;
use App\Model\Master\OrdersItem;
use App\Model\Master\Package;
use App\Model\Master\PaymentTransaction;
use App\Services\MailService;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Http\Controllers\StripeController;

class CheckoutController extends Controller
{
    public function processCheckout(Request $request)
    {

        $arrDataForClientPackages = [];
        $strPaymentMethodId = $strPaymentDescription = NULL;
        $boolPaymentFailed = FALSE;
        $intTotalAmount = 0;

        //Validations
        if ($request->get('payment_method') != '0') {
            $this->validate($request, [
                'payment_method' => 'required|string'
            ]);
        } else {
            $this->validate($request, [
                'full_name' => 'required|string',
                'line1' => 'required|string',
                'city' => 'required|string',
                'state' => 'required|string',
                'country' => 'required|string',
                'postal_code' => 'required|numeric',
                'number' => 'required',
                'exp_month' => 'required|numeric|digits:2',
                'exp_year' => 'required|numeric|digits:4',
                'cvc' => 'required|numeric|digits_between:3,4'
            ]);
        }

        if ($request->get('request_type') == 'recharge') {
            $this->validate($request, [
                'amount' => 'required|numeric'
            ]);
        }

        try {
            $objStripeController = new StripeController($request);
            $objCartController = new CartController();
            Log::info('reached', ['objStripeController' => $objStripeController]);
            //Handler for recharge request
            if ($request->get('request_type') == 'recharge') {
                $intTotalAmount = $request->get('amount');
                $strPaymentDescription = "Recharge";
            } else {
                $intTotalAmount = $objCartController->calculateCartTotalAmount($request->auth->parent_id);
                $strPaymentDescription = "Package purchase";
            }

            if ($request->get('payment_method') != '0') {
                $strPaymentMethodId = $request->payment_method;

                //order table entry
                $objOrder = new Order();
                $objOrder->client_id = $request->auth->parent_id;
                $objOrder->net_amount = $intTotalAmount;
                $objOrder->gross_amount = $intTotalAmount;
                $objOrder->status = 'initiated';
                $objOrder->saveOrFail();

            } else {

                //order table entry
                $objOrder = new Order();
                $objOrder->client_id = $request->auth->parent_id;
                $objOrder->net_amount = $intTotalAmount;
                $objOrder->gross_amount = $intTotalAmount;
                $objOrder->status = 'initiated';
                $objOrder->saveOrFail();

                //Create stripe customer ID if not present
                if ($request->auth->stripe_customer_id) {
                    $objStripeController->getStripeCustomerId();
                }

                //Fetch customer associated Payment Methods
                $customerPaymentMethods = $objStripeController->fetchStripeCustomerPaymentMethod();

                //Create payment Method
                $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET'));
                $paymentMethod = $stripe->paymentMethods->create([
                    'type' => 'card',
                    'card' => [
                        'number' => $request->number,
                        'exp_month' => $request->exp_month,
                        'exp_year' => $request->exp_year,
                        'cvc' => $request->cvc,
                    ],
                    'billing_details' => [
                        'name' => $request->full_name,
                        'address' => [
                            'city' => $request->city,
                            'country' => $request->country,
                            'line1' => $request->line1,
                            'postal_code' => $request->postal_code,
                            'state' => $request->state,
                        ]
                    ]
                ]);

                $strPaymentMethodId = $paymentMethod->id;

                //Attach Customer And Payment Method
                $objStripeController->attachCustomerToPaymentMethod($paymentMethod->id);

                //Update default_payment_method for the first payment method for that customer
                if (empty($customerPaymentMethods->data)) {
                    $objStripeController->setDefaultPaymentMethod($paymentMethod->id);
                }
            }

            //Payment processing
            $chargeResponse = $objStripeController->chargeUsingStripe($intTotalAmount, $strPaymentMethodId, $strPaymentDescription);

            if ($chargeResponse->status !== 'succeeded') {
                $customerPaymentMethods = $objStripeController->fetchStripeCustomerPaymentMethod();
                foreach ($customerPaymentMethods->data ?? [] as $paymentMethod) {
                    if ($paymentMethod->id === $strPaymentMethodId) {
                        continue;
                    }
                    $chargeResponse = $objStripeController->chargeUsingStripe($intTotalAmount, $paymentMethod->id, $strPaymentDescription);
                    if ($chargeResponse->status === 'succeeded') {
                        break;
                    }
                }
            }

            //payment_transactions table entry
            $objPaymentTransactions = new PaymentTransaction();
            $objPaymentTransactions->order_id = $objOrder->id;
            $objPaymentTransactions->payment_gateway_type = 'stripe';
            $objPaymentTransactions->response = $chargeResponse;

            //order table status update
            if ($chargeResponse->status == 'succeeded') {
                $objPaymentTransactions->status = 'success';
                $objOrder->status = 'success';
            } elseif ($chargeResponse->status == 'requires_payment_method') {
                $objPaymentTransactions->status = 'failed';
                $objOrder->status = 'failed';
                $boolPaymentFailed = TRUE;
            } elseif ($chargeResponse->status == 'requires_action') {
                $objPaymentTransactions->status = 'failed';
                $objOrder->status = 'failed';
                $boolPaymentFailed = TRUE;
            }

            $objPaymentTransactions->saveOrFail();
            $objOrder->saveOrFail();

            if ($boolPaymentFailed) {
                Log::debug("CheckoutController.processCheckout", [
                    "clientId" => $request->auth->parent_id,
                    "user" => $request->auth,
                    "orderId" => $objOrder->id,
                    "message" => 'Payment processing failed'
                ]);

                //Send Email in case of failed transaction
                $context["clientId"] = $request->auth->parent_id;
                $context["userId"] = $request->auth->id;
                $context["orderId"] = $objOrder->id;
                $context["paymentTransactions"] = $objPaymentTransactions->id;

                $emailBody = view('emails.errorNotification', compact('context'))->render();
                $genericMail = new GenericMail(
                    "Payment processing failed",
                    [
                        "address" => "rohit@cafmotel.com",
                        "name" => "Cafmotel Order Process"
                    ],
                    $emailBody
                );

                $smtpSetting = SmtpSetting::getBySenderType('mysql_' . $request->auth->parent_id, "system");
                $mailService = new MailService($request->auth->parent_id, $genericMail, $smtpSetting);
                $mailService->sendEmail([env('ROHIT_EMAIL'), env('VIJAY_EMAIL')]);

                return $this->failResponse("Payment processing failed!", []);
            }

            //For recharge : wallet & wallet_transaction entry
            if ($request->get('request_type') == 'recharge') {

                //Add amount into client_xxx.wallet
                $res = wallet::creditCharge($intTotalAmount, $request->auth->parent_id, 'USD');

                //ledger entry into client_xxx.wallet_transactions
                $objWalletTransaction = new WalletTransaction();
                $objWalletTransaction->setConnection("mysql_" . $request->auth->parent_id);
                $objWalletTransaction->currency_code = 'USD';
                $objWalletTransaction->amount = $intTotalAmount;
                $objWalletTransaction->transaction_type = 'credit';
                $objWalletTransaction->transaction_reference = '';
                $objWalletTransaction->description = 'Recharge';
                $objWalletTransaction->saveOrFail();

                return $this->successResponse("Recharge successful", []);
            } else {
                //fetch packages & cart items
                $packages = Package::all()->toArray();
                $packagesRekeyed = UserPackagesController::rekeyArray($packages, 'key');
                $cartItems = Cart::on("mysql_" . $request->auth->parent_id)->get()->toArray();

                foreach ($cartItems as $cartItem) {
                    //Entry into order_items
                    $objOrdersItem = new OrdersItem();
                    $objOrdersItem->order_id = $objOrder->id;
                    $objOrdersItem->description = 'package purchase';
                    $objOrdersItem->package_key = $cartItem['package_key'];
                    $objOrdersItem->quantity = $cartItem['quantity'];
                    $objOrdersItem->billed = $cartItem['billed'];
                    $objOrdersItem->amount = $cartItem['quantity'] * $packagesRekeyed[$cartItem['package_key']][ClientPackage::$billingMapping[$cartItem['billed']]];
                    $objOrdersItem->saveOrFail();

                    if (array_key_exists($cartItem['package_key'] . "_" . $cartItem['billed'], $arrDataForClientPackages)) {
                        $arrDataForClientPackages[$cartItem['package_key'] . "_" . $cartItem['billed']]['quantity'] += $cartItem['quantity'];
                    } else {
                        $arrDataForClientPackages[$cartItem['package_key'] . "_" . $cartItem['billed']] = $cartItem;
                    }
                }

                //Terminate current trial package if active
                $trialPackageAssigned = ClientPackage::where('client_id', '=', $request->auth->parent_id)->where('package_key', '=', Package::TRIAL_PACKAGE_KEY)->where('end_time', '>=', date('Y-m-d h:i:s'))->get();
                if (!$trialPackageAssigned->isEmpty()) {
                    $trialPackageAssigned[0]->end_time = Carbon::now();
                    $trialPackageAssigned[0]->expiry_time = Carbon::now();
                    $trialPackageAssigned[0]->saveOrFail();
                }

                //If current user NOT associated with any package THEN assign new one
                $clientPackages = ClientPackage::where('client_id', '=', $request->auth->parent_id)->where('end_time', '>=', date('Y-m-d h:i:s'))->get()->toArray();
                $clientPackagesRekeyed = UserPackagesController::rekeyArray($clientPackages, 'id');

                $userPackages = DB::connection('mysql_' . $request->auth->parent_id)->table('user_packages')->get()->toArray();
                $intClientPackageId = UserPackagesController::getPackageAssignedToUser($userPackages, $request->auth->id);

                foreach ($arrDataForClientPackages as $cartItemPackageWise) {
                    $paymentAmount = $cartItemPackageWise['quantity'] * $packagesRekeyed[$cartItemPackageWise['package_key']][ClientPackage::$billingMapping[$cartItemPackageWise['billed']]];

                    //End date for next billing cycle
                    $strEndDate = ClientPackage::getEndDateAsPerBillingCycle($cartItemPackageWise['billed']);

                    //entry into client_packages
                    $objClientPackage = new ClientPackage();
                    $objClientPackage->client_id = $request->auth->parent_id;
                    $objClientPackage->package_key = $cartItemPackageWise['package_key'];
                    $objClientPackage->quantity = $cartItemPackageWise['quantity'];
                    $objClientPackage->start_time = Carbon::now();
                    $objClientPackage->end_time = $strEndDate;
                    $objClientPackage->expiry_time = $strEndDate;
                    $objClientPackage->billed = $cartItemPackageWise['billed'];
                    $objClientPackage->payment_cent_amount = $paymentAmount * 100;
                    $objClientPackage->payment_time = Carbon::now();
                    $objClientPackage->payment_method = "stripe";
                    $objClientPackage->psp_reference = time();
                    $objClientPackage->saveOrFail();

                    //entries into user_packages
                    for ($i = 0; $i < $cartItemPackageWise['quantity']; $i++) {
                        $objUserPackage = new UserPackage();
                        $objUserPackage->setConnection('mysql_' . $request->auth->parent_id);
                        $objUserPackage->client_package_id = $objClientPackage->id;
                        $objUserPackage->free_call_minutes = $packagesRekeyed[$cartItemPackageWise['package_key']]['free_call_minute_monthly'];
                        $objUserPackage->free_sms = $packagesRekeyed[$cartItemPackageWise['package_key']]['free_sms_monthly'];
                        $objUserPackage->free_fax = $packagesRekeyed[$cartItemPackageWise['package_key']]['free_fax_monthly'];
                        $objUserPackage->free_emails = $packagesRekeyed[$cartItemPackageWise['package_key']]['free_emails_monthly'];
                        $objUserPackage->free_reset_time = Carbon::now()->addMonth();

                        if ($i == 0 && !$intClientPackageId) {
                            $objUserPackage->user_id = $request->auth->id;
                        } elseif (!array_key_exists($intClientPackageId, $clientPackagesRekeyed)) {
                            $objUserPackage->user_id = $request->auth->id;
                        }

                        $objUserPackage->saveOrFail();
                    }
                }

                //remove all entries from cart table
                Cart::on("mysql_" . $request->auth->parent_id)->delete();
                return $this->successResponse("Order completed successfully", []);
            }

        } catch (\Throwable $exception) {
            Log::debug("CheckoutController.processCheckout", [
                "clientId" => $request->auth->parent_id,
                "user" => $request->auth,
                "message" => 'Failed to place order'
            ]);
            return $this->failResponse("Failed to place order", [$exception->getMessage()], $exception);
        }
    }

    public function processSubscriptionCheckout(Request $request)
    {
        $arrDataForClientPackages = [];
        $strPaymentMethodId = $strPaymentDescription = NULL;
        $boolPaymentFailed = FALSE;
        $intTotalAmount = 0;

        // Validations
        if ($request->get('payment_method') != '0') {
            $this->validate($request, [
                'payment_method' => 'required|string'
            ]);
        } else {
            $this->validate($request, [
                'full_name' => 'required|string',
                'line1' => 'required|string',
                'city' => 'required|string',
                'state' => 'required|string',
                'country' => 'required|string',
                'postal_code' => 'required|numeric',
                'number' => 'required',
                'exp_month' => 'required|numeric|digits:2',
                'exp_year' => 'required|numeric|digits:4',
                'cvc' => 'required|numeric|digits_between:3,4'
            ]);
        }

        try {
            $objStripeController = new StripeController($request);
            $objCartController = new CartController();
            Log::info('CheckoutController.processCheckout started', ['clientId' => $request->auth->parent_id]);

            // Calculate total amount for package purchase
            $intTotalAmount = $objCartController->calculateCartTotalAmount($request->auth->parent_id);
            $strPaymentDescription = "Package purchase";

            // Initialize Stripe client
            $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET'));

            // Order table entry
            $objOrder = new Order();
            $objOrder->client_id = $request->auth->parent_id;
            $objOrder->net_amount = $intTotalAmount;
            $objOrder->gross_amount = $intTotalAmount;
            $objOrder->status = 'initiated';
            $objOrder->saveOrFail();

            // Create or retrieve customer ID
            if (!$request->auth->stripe_customer_id) {
                $objStripeController->getStripeCustomerId();
            }
            $customerId = $request->auth->stripe_customer_id;

            // Validate customer exists
            try {
                $stripe->customers->retrieve($customerId);
                Log::info('Customer validated', ['customer_id' => $customerId]);
            } catch (\Exception $e) {
                Log::error('Invalid customer ID', ['customer_id' => $customerId, 'error' => $e->getMessage()]);
                throw new \Exception('Invalid customer ID: ' . $e->getMessage());
            }

            // Set payment method
            if ($request->get('payment_method') != '0') {
                $strPaymentMethodId = $request->payment_method;
            } else {
                $paymentMethod = $stripe->paymentMethods->create([
                    'type' => 'card',
                    'card' => [
                        'number' => $request->number,
                        'exp_month' => $request->exp_month,
                        'exp_year' => $request->exp_year,
                        'cvc' => $request->cvc,
                    ],
                    'billing_details' => [
                        'name' => $request->full_name,
                        'address' => [
                            'city' => $request->city,
                            'country' => $request->country,
                            'line1' => $request->line1,
                            'postal_code' => $request->postal_code,
                            'state' => $request->state,
                        ]
                    ]
                ]);
                $strPaymentMethodId = $paymentMethod->id;
            }

            // Validate and attach payment method
            try {
                $objStripeController->attachCustomerToPaymentMethod($strPaymentMethodId);
                Log::info('Payment method attached', ['payment_method_id' => $strPaymentMethodId]);
            } catch (\Exception $e) {
                Log::error('Failed to attach payment method', ['payment_method_id' => $strPaymentMethodId, 'error' => $e->getMessage()]);
                throw new \Exception('Failed to attach payment method: ' . $e->getMessage());
            }

            // Set default payment method if needed
            $customerPaymentMethods = $objStripeController->fetchStripeCustomerPaymentMethod();
            if (empty($customerPaymentMethods->data)) {
                $objStripeController->setDefaultPaymentMethod($strPaymentMethodId);
                Log::info('Default payment method set', ['payment_method_id' => $strPaymentMethodId]);
            }

            // Fetch packages & cart items for subscription
            $packages = Package::all()->toArray();
            $packagesRekeyed = UserPackagesController::rekeyArray($packages, 'key');
            $cartItems = Cart::on("mysql_" . $request->auth->parent_id)->get()->toArray();
            Log::info('Cart items fetched', ['cart_items' => $cartItems]);

            $subscriptionItems = [];
            foreach ($cartItems as $cartItem) {
                $package = Package::where('key', $cartItem['package_key'])->first();
                if ($package) {
                    Log::info('Package found', ['package_key' => $cartItem['package_key'], 'stripe_product_id' => $package->stripe_product_id]);
                    if ($package->stripe_product_id) {
                        // Fetch active monthly Price ID for the Product ID
                        $prices = $stripe->prices->all([
                            'product' => $package->stripe_product_id,
                            'active' => true,
                            'recurring' => ['interval' => 'month'] // Enforce monthly billing
                        ]);
                        $price = $prices->data[0] ?? null;
                        if ($price) {
                            $subscriptionItems[] = [
                                'price' => $price->id,
                                'quantity' => $cartItem['quantity'],
                            ];
                            Log::info('Price ID found for product', [
                                'product_id' => $package->stripe_product_id,
                                'price_id' => $price->id,
                                'interval' => 'month'
                            ]);
                        } else {
                            Log::warning('No active monthly price found for product', [
                                'product_id' => $package->stripe_product_id,
                                'package_key' => $cartItem['package_key']
                            ]);
                        }
                    } else {
                        Log::warning('Package missing stripe_product_id', ['package_key' => $cartItem['package_key']]);
                    }
                } else {
                    Log::warning('Package not found for package_key', ['package_key' => $cartItem['package_key']]);
                }
            }

            // Break if no valid subscription items
            if (empty($subscriptionItems)) {
                Log::error('No valid subscription items found', ['order_id' => $objOrder->id, 'cart_items' => $cartItems]);
                throw new \Exception('No valid subscription items found for the cart');
            }

            // Create subscription
            $subscription = null;
            try {
                $subscription = $stripe->subscriptions->create([
                    'customer' => $customerId,
                    'items' => $subscriptionItems,
                    'default_payment_method' => $strPaymentMethodId,
                    'expand' => ['latest_invoice.payment_intent'],
                ]);
                Log::info('Subscription created successfully', [
                    'subscription_id' => $subscription->id,
                    'status' => $subscription->status,
                    'order_id' => $objOrder->id,
                ]);

                // Store subscription ID in order
                $objOrder->stripe_subscription_id = $subscription->id;
                $objOrder->status = $subscription->status === 'active' ? 'success' : 'pending';
                $objOrder->save();
            } catch (\Exception $e) {
                Log::error('Failed to create subscription', [
                    'error' => $e->getMessage(),
                    'order_id' => $objOrder->id,
                    'customer_id' => $customerId,
                    'subscription_items' => $subscriptionItems,
                ]);
                throw new \Exception('Failed to create subscription: ' . $e->getMessage());
            }

            // Create payment transaction for subscription’s first invoice
            $objPaymentTransactions = new PaymentTransaction();
            $objPaymentTransactions->order_id = $objOrder->id;
            $objPaymentTransactions->payment_gateway_type = 'stripe';
            $objPaymentTransactions->response = $subscription->latest_invoice->payment_intent;
            $objPaymentTransactions->status = $subscription->status === 'active' ? 'success' : 'pending';
            $objPaymentTransactions->saveOrFail();

            // If subscription is not active, fall back to one-time payment
            if ($subscription->status !== 'active') {
                $chargeResponse = $objStripeController->chargeUsingStripe($intTotalAmount, $strPaymentMethodId, $strPaymentDescription);

                // Update payment transaction for one-time payment
                $objPaymentTransactions->response = $chargeResponse;
                if ($chargeResponse->status == 'succeeded') {
                    $objPaymentTransactions->status = 'success';
                    $objOrder->status = 'success';
                } elseif ($chargeResponse->status == 'requires_payment_method') {
                    $objPaymentTransactions->status = 'failed';
                    $objOrder->status = 'failed';
                    $boolPaymentFailed = TRUE;
                } elseif ($chargeResponse->status == 'requires_action') {
                    $objPaymentTransactions->status = 'failed';
                    $objOrder->status = 'failed';
                    $boolPaymentFailed = TRUE;
                }
                $objPaymentTransactions->saveOrFail();
                $objOrder->saveOrFail();
            }

            if ($boolPaymentFailed) {
                Log::debug("CheckoutController.processCheckout", [
                    "clientId" => $request->auth->parent_id,
                    "user" => $request->auth,
                    "orderId" => $objOrder->id,
                    "message" => 'Payment processing failed'
                ]);

                // Send Email in case of failed transaction
                $context["clientId"] = $request->auth->parent_id;
                $context["userId"] = $request->auth->id;
                $context["orderId"] = $objOrder->id;
                $context["paymentTransactions"] = $objPaymentTransactions->id;

                $emailBody = view('emails.errorNotification', compact('context'))->render();
                $genericMail = new GenericMail(
                    "Payment processing failed",
                    [
                        "address" => "rohit@cafmotel.com",
                        "name" => "Cafmotel Order Process"
                    ],
                    $emailBody
                );

                $smtpSetting = SmtpSetting::getBySenderType('mysql_' . $request->auth->parent_id, "system");
                $mailService = new MailService($request->auth->parent_id, $genericMail, $smtpSetting);
                $mailService->sendEmail([env('ROHIT_EMAIL'), env('VIJAY_EMAIL')]);

                return $this->failResponse("Payment processing failed!", []);
            }

            // Process cart items
            foreach ($cartItems as $cartItem) {
                // Entry into order_items
                $objOrdersItem = new OrdersItem();
                $objOrdersItem->order_id = $objOrder->id;
                $objOrdersItem->description = 'package purchase';
                $objOrdersItem->package_key = $cartItem['package_key'];
                $objOrdersItem->quantity = $cartItem['quantity'];
                $objOrdersItem->billed = $cartItem['billed'];
                $objOrdersItem->amount = $cartItem['quantity'] * $packagesRekeyed[$cartItem['package_key']][ClientPackage::$billingMapping[$cartItem['billed']]];
                $objOrdersItem->saveOrFail();

                if (array_key_exists($cartItem['package_key'] . "_" . $cartItem['billed'], $arrDataForClientPackages)) {
                    $arrDataForClientPackages[$cartItem['package_key'] . "_" . $cartItem['billed']]['quantity'] += $cartItem['quantity'];
                } else {
                    $arrDataForClientPackages[$cartItem['package_key'] . "_" . $cartItem['billed']] = $cartItem;
                }
            }

            // Terminate current trial package if active
            $trialPackageAssigned = ClientPackage::where('client_id', '=', $request->auth->parent_id)
                ->where('package_key', '=', Package::TRIAL_PACKAGE_KEY)
                ->where('end_time', '>=', date('Y-m-d h:i:s'))
                ->get();
            if (!$trialPackageAssigned->isEmpty()) {
                $trialPackageAssigned[0]->end_time = Carbon::now();
                $trialPackageAssigned[0]->expiry_time = Carbon::now();
                $trialPackageAssigned[0]->saveOrFail();
            }

            // If current user NOT associated with any package THEN assign new one
            $clientPackages = ClientPackage::where('client_id', '=', $request->auth->parent_id)
                ->where('end_time', '>=', date('Y-m-d h:i:s'))
                ->get()->toArray();
            $clientPackagesRekeyed = UserPackagesController::rekeyArray($clientPackages, 'id');

            $userPackages = DB::connection('mysql_' . $request->auth->parent_id)->table('user_packages')->get()->toArray();
            $intClientPackageId = UserPackagesController::getPackageAssignedToUser($userPackages, $request->auth->id, $clientPackagesRekeyed);

            foreach ($arrDataForClientPackages as $cartItemPackageWise) {
                $paymentAmount = $cartItemPackageWise['quantity'] * $packagesRekeyed[$cartItemPackageWise['package_key']][ClientPackage::$billingMapping[$cartItemPackageWise['billed']]];

                // End date for next billing cycle
                $strEndDate = ClientPackage::getEndDateAsPerBillingCycle($cartItemPackageWise['billed']);

                // Entry into client_packages
                $objClientPackage = new ClientPackage();
                $objClientPackage->client_id = $request->auth->parent_id;
                $objClientPackage->package_key = $cartItemPackageWise['package_key'];
                $objClientPackage->quantity = $cartItemPackageWise['quantity'];
                $objClientPackage->start_time = Carbon::now();
                $objClientPackage->end_time = $strEndDate;
                $objClientPackage->expiry_time = $strEndDate;
                $objClientPackage->billed = $cartItemPackageWise['billed'];
                $objClientPackage->payment_cent_amount = $paymentAmount * 100;
                $objClientPackage->payment_time = Carbon::now();
                $objClientPackage->payment_method = "stripe";
                $objClientPackage->psp_reference = time();
                $objClientPackage->saveOrFail();

                // Entries into user_packages
                for ($i = 0; $i < $cartItemPackageWise['quantity']; $i++) {
                    $objUserPackage = new UserPackage();
                    $objUserPackage->setConnection('mysql_' . $request->auth->parent_id);
                    $objUserPackage->client_package_id = $objClientPackage->id;
                    $objUserPackage->free_call_minutes = $packagesRekeyed[$cartItemPackageWise['package_key']]['free_call_minute_monthly'];
                    $objUserPackage->free_sms = $packagesRekeyed[$cartItemPackageWise['package_key']]['free_sms_monthly'];
                    $objUserPackage->free_fax = $packagesRekeyed[$cartItemPackageWise['package_key']]['free_fax_monthly'];
                    $objUserPackage->free_emails = $packagesRekeyed[$cartItemPackageWise['package_key']]['free_emails_monthly'];
                    $objUserPackage->free_reset_time = Carbon::now()->addMonth();

                    if ($i == 0 && !$intClientPackageId) {
                        $objUserPackage->user_id = $request->auth->id;
                    } elseif (!array_key_exists($intClientPackageId, $clientPackagesRekeyed)) {
                        $objUserPackage->user_id = $request->auth->id;
                    }

                    $objUserPackage->saveOrFail();
                }
            }

            // Remove all entries from cart table
            Cart::on("mysql_" . $request->auth->parent_id)->delete();
            return $this->successResponse("Order completed successfully", []);

        } catch (\Throwable $exception) {
            Log::debug("CheckoutController.processCheckout", [
                "clientId" => $request->auth->parent_id,
                "user" => $request->auth,
                "message" => 'Failed to place order',
                "error" => $exception->getMessage()
            ]);
            return $this->failResponse("Failed to place order", [$exception->getMessage()], $exception);
        }
    }

    public function processRechargeAuto(Request $request)
    {
        $strPaymentMethodId = $strPaymentDescription = NULL;
        $boolPaymentFailed = FALSE;
        $intTotalAmount = 0;

        // Validations
        $this->validate($request, [
            'amount' => 'required|numeric'
        ]);

        try {
            $objStripeController = new StripeController($request);
            Log::info('reached', ['objStripeController' => $objStripeController]);

            // Set recharge-specific variables
            $intTotalAmount = $request->get('amount');
            $strPaymentDescription = "Recharge";

            // Order table entry
            $objOrder = new Order();
            $objOrder->client_id = $request->auth->parent_id;
            $objOrder->net_amount = $intTotalAmount;
            $objOrder->gross_amount = $intTotalAmount;
            $objOrder->status = 'initiated';
            $objOrder->saveOrFail();

            // Ensure Stripe customer ID exists (create if not present)
            $stripeCustomerId = $objStripeController->getStripeCustomerId();
            if (!$request->auth->stripe_customer_id) {
                $request->auth->stripe_customer_id = $stripeCustomerId;
                $request->auth->saveOrFail();
            }

            // Fetch customer associated Payment Methods
            $customerPaymentMethods = $objStripeController->fetchStripeCustomerPaymentMethod();

            if (empty($customerPaymentMethods->data)) {
                return $this->failResponse("No payment methods available in your Stripe account!", []);
            }

            // Get the Stripe customer to determine default payment method
            $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET'));
            $customer = $stripe->customers->retrieve($request->auth->stripe_customer_id);
            $defaultPmId = $customer->invoice_settings->default_payment_method;

            // If no default, use the first available
            if (!$defaultPmId) {
                $defaultPmId = $customerPaymentMethods->data[0]->id;
            }

            $strPaymentMethodId = $defaultPmId;

            // Payment processing - start with default
            $chargeResponse = $objStripeController->chargeUsingStripe($intTotalAmount, $strPaymentMethodId, $strPaymentDescription);

            // Try other payment methods if the default fails
            if ($chargeResponse->status !== 'succeeded') {
                foreach ($customerPaymentMethods->data as $paymentMethod) {
                    if ($paymentMethod->id === $strPaymentMethodId) {
                        continue;
                    }
                    $chargeResponse = $objStripeController->chargeUsingStripe($intTotalAmount, $paymentMethod->id, $strPaymentDescription);
                    if ($chargeResponse->status === 'succeeded') {
                        break;
                    }
                }
            }

            // Payment transactions table entry
            $objPaymentTransactions = new PaymentTransaction();
            $objPaymentTransactions->order_id = $objOrder->id;
            $objPaymentTransactions->payment_gateway_type = 'stripe';
            $objPaymentTransactions->response = $chargeResponse;

            // Order table status update
            if ($chargeResponse->status == 'succeeded') {
                $objPaymentTransactions->status = 'success';
                $objOrder->status = 'success';
            } elseif ($chargeResponse->status == 'requires_payment_method') {
                $objPaymentTransactions->status = 'failed';
                $objOrder->status = 'failed';
                $boolPaymentFailed = TRUE;
            } elseif ($chargeResponse->status == 'requires_action') {
                $objPaymentTransactions->status = 'failed';
                $objOrder->status = 'failed';
                $boolPaymentFailed = TRUE;
            }

            $objPaymentTransactions->saveOrFail();
            $objOrder->saveOrFail();

            if ($boolPaymentFailed) {
                Log::debug("CheckoutController.processRecharge", [
                    "clientId" => $request->auth->parent_id,
                    "user" => $request->auth,
                    "orderId" => $objOrder->id,
                    "message" => 'Payment processing failed'
                ]);

                // Send Email in case of failed transaction
                $context["clientId"] = $request->auth->parent_id;
                $context["userId"] = $request->auth->id;
                $context["orderId"] = $objOrder->id;
                $context["paymentTransactions"] = $objPaymentTransactions->id;

                $emailBody = view('emails.errorNotification', compact('context'))->render();
                $genericMail = new GenericMail(
                    "Payment processing failed",
                    [
                        "address" => "rohit@cafmotel.com",
                        "name" => "Cafmotel Order Process"
                    ],
                    $emailBody
                );

                $smtpSetting = SmtpSetting::getBySenderType('mysql_' . $request->auth->parent_id, "system");
                $mailService = new MailService($request->auth->parent_id, $genericMail, $smtpSetting);
                $mailService->sendEmail([env('ROHIT_EMAIL'), env('VIJAY_EMAIL')]);

                return $this->failResponse("Payment processing failed!", []);
            }

            // Add amount into client_xxx.wallet
            $res = wallet::creditCharge($intTotalAmount, $request->auth->parent_id, 'USD');

            // Ledger entry into client_xxx.wallet_transactions
            $objWalletTransaction = new WalletTransaction();
            $objWalletTransaction->setConnection("mysql_" . $request->auth->parent_id);
            $objWalletTransaction->currency_code = 'USD';
            $objWalletTransaction->amount = $intTotalAmount;
            $objWalletTransaction->transaction_type = 'credit';
            $objWalletTransaction->transaction_reference = '';
            $objWalletTransaction->description = 'Recharge';
            $objWalletTransaction->saveOrFail();

            return $this->successResponse("Recharge successful", []);

        } catch (\Throwable $exception) {
            Log::debug("CheckoutController.processRecharge", [
                "clientId" => $request->auth->parent_id,
                "user" => $request->auth,
                "message" => 'Failed to process recharge'
            ]);
            return $this->failResponse("Failed to process recharge", [$exception->getMessage()], $exception);
        }
    }
}
