<?php

namespace App\Http\Controllers;

use App\Classes\MikrotikService\Mikrotik;
use App\Classes\MikrotikService\SyncWithMk;
use App\Classes\SMS\ResellerRechargeSms;
use App\Http\Controllers\Clients\IdEnableDisableController;
use App\Models\Balance;
use App\Models\Client;
use App\Models\CustomerAccount;
use App\Models\Packages;
use App\Models\Pop;
use App\Models\ReselleBalanceLogReport;
use App\Models\ResellerSmsGetway;
use App\Models\SubPackage;
use App\Models\SubResellerBalanceLogReport;
use App\Services\CommissionService;
use App\Services\ExpirationService;
use App\Services\PriceCalculate;
use Brian2694\Toastr\Facades\Toastr;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class DynamicRechargeController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:dynamic-recharge', ['only' => ['index']]);
    }

    public function dynamicRechargeProcess($request)
    {
        ini_set('memory_limit', '512M');
        set_time_limit(0);
        if ($request->type !== 'Recharge' || empty($request->ids)) {
            return ['status' => 'error', 'message' => 'Invalid request'];
        }

        $results = [
            'successful' => [],
            'failed' => [],
            'total' => count($request->ids)
        ];


        $uniqueString = $request->uuid;
        $batchSize = 10; // Process 10 at a time to limit lock duration
        $batches = array_chunk($request->ids, $batchSize);

        foreach ($batches as $batch) {
            $successFullIds = [];
            foreach ($batch as $id) {
                // Individual transaction per customer - minimal lock time
                try {
                    DB::beginTransaction();

                    $status = $this->doCustomerRecharge($id, $request->recharge_day, $uniqueString);

                    if ($status !== 'success') {
                        DB::rollBack();
                        $results['failed'][] = [
                            'id' => $id,
                            'reason' => $this->getErrorMessage($status)
                        ];
                        continue;
                    } else {
                        $successFullIds[] = $id;
                    }

                    DB::commit();
                    $results['successful'][] = $id;

                    // Send SMS asynchronously to avoid blocking
                    try {
                        $this->resellerCustomerRechargeSms($successFullIds);
                    } catch (\Exception $e) {

                        // Don't fail the recharge if SMS fails
                    }
                } catch (\Throwable $th) {
                    DB::rollBack();
                    $results['failed'][] = [
                        'id' => $id,
                        'reason' => $th->getMessage()
                    ];
                }

                // Small delay to prevent overwhelming the database
                usleep(10000); // 10ms between customers
            }
        }

        return $this->formatResponse($results);
    }

    private function getErrorMessage($status)
    {
        switch ($status) {
            case 'balance_error':
                return 'Insufficient Balance';
            case 'sub_package_error':
                return 'No Sub Package';
            default:
                return 'Unknown error: ' . $status;
        }
    }

    private function formatResponse($results)
    {
        $successCount = count($results['successful']);
        $failCount = count($results['failed']);

        if ($failCount === 0) {
            return [
                'status' => 'success',
                'message' => "All {$successCount} recharges completed",
                'data' => $results
            ];
        }

        if ($successCount === 0) {
            return [
                'status' => 'error',
                'message' => "All {$failCount} recharges failed {$results['failed'][0]['reason']}",
                'data' => $results
            ];
        }

        return [
            'status' => 'partial',
            'message' => "{$successCount} succeeded, {$failCount} failed recharges {$results['failed'][0]['reason']}",
            'data' => $results
        ];
    }

    public function doCustomerRecharge($id, $recharge_day, $uniqueString)
    {
        $user = Client::find($id);

        Log::info('Dynamic Recharge user id before: ' . $user->id . 'status: ' . $user->clients_status);

        $pop  = Pop::with('reseller')->find($user->pop_id);
        if ($pop->bill_generate == 'yes') {
            return false;
        }
        $package = Packages::find($user->package_id);
        $resellerBalance = Balance::getBalance('reseller', $pop->reseller_id);
        $expire = Carbon::parse($user->expire_date);
        $cur = today();
        if (checkSettings('expire_billing_change_today_from_billing_date') == 'enable' && $expire < today()) {

            $nextExpire = Carbon::parse($cur)->addDays($recharge_day - 1);
            // $totalDay = today()->diffInDays($nextExpire);
            $totalDay = $recharge_day;
            $action_days_message = 'Total ' . $totalDay . ' days. From ' . $cur . ' To ' . $nextExpire;
            $totalCost = PriceCalculate::calculate(today()->daysInMonth, $package->package_rate, $totalDay);
        } else {
            if ($expire < today() && Carbon::parse($user->expire_date)->addDays($recharge_day) < today()) {
                if (date('t') < $user->billing_cycle) {
                    $user->billing_cycle = date('t');
                    $user->save();
                }
                $nextExpire = Carbon::parse($cur)->addDays($recharge_day - 1);
                // $totalDay = today()->diffInDays($nextExpire);
                $totalDay = $recharge_day;
                $action_days_message = 'Total ' . $totalDay . ' days. From ' . $cur . ' To ' . $nextExpire;
                $totalCost = PriceCalculate::calculate(today()->daysInMonth, $package->package_rate, $totalDay);
            } else {
                $nextExpire = Carbon::parse($user->expire_date)->addDays($recharge_day);
                $totalDay = $nextExpire->diffInDays($user->expire_date) + 0;
                $action_days_message = 'Total ' . $totalDay . ' days. From ' . $user->expire_date . ' To ' . $nextExpire;
                $totalCost = PriceCalculate::calculate(today()->daysInMonth, $package->package_rate, $totalDay);
            }
        }

        $reseller_id = $pop->reseller_id;

        if ($resellerBalance >= $totalCost) {


            Balance::balanceDeductForUserRecharge('reseller', $reseller_id, $totalCost); // balance deduct after subreseller balance deduct
            $action = "Recharge For " . $action_days_message . " . For package " . $package->package_name . " cost BDT " . $totalCost;
            $resellerBalanceAfterRecharge  = Balance::getBalance('reseller', $pop->reseller_id);

            $resellerBalanceLogReport =  ReselleBalanceLogReport::create([
                'reseller_id' => $reseller_id,
                'client_id'   => $id,
                'action'      => $action,
                'amount'      => $totalCost,
                'remarks'     => 'Created BY ' . Auth::user()->email,
                'reseller_balance' => $resellerBalance,
                'after_balance' => $resellerBalanceAfterRecharge,
                'uniqueId'    => $uniqueString . $id,
                'pop_id'      => $pop->id,
                'commission_amount' => getCommissionForResellerRecharge($id, $totalCost),
                'reseller_commission_percentage' => $pop->reseller->commission_percentage,
                'pop_commission_percentage' => $pop->commission_percentage,

            ]);

            if ($pop->billable == 'yes') {
                // Balance::balanceDeductForUserRecharge('reseller', $reseller_id, $totalCost);
                if ($pop->subreseller == 'yes') {
                    $subPackage = SubPackage::find($user->sub_package_id);
                    $popBalance  = Balance::getBalance('pop', $pop->id);

                    if (empty($subPackage)) {
                        return 'sub_package_error';
                    }
                    $cur = today();
                    if (checkSettings('expire_billing_change_today_from_billing_date') == 'enable' && $expire < today()) {

                        $nextExpire = Carbon::parse($cur)->addDays($recharge_day - 1);
                        // $totalDay = today()->diffInDays($nextExpire);
                        $totalDay = $recharge_day;
                        $action_days_message = 'Total ' . $totalDay . ' days. From ' . $cur . ' To ' . $nextExpire;
                        $subTotalCost = PriceCalculate::calculate(today()->daysInMonth, $subPackage->rate, $totalDay);
                    } else {
                        if ($expire < today() && Carbon::parse($user->expire_date)->addDays($recharge_day) < today()) {
                            $nextExpire = Carbon::parse($cur)->addDays($recharge_day - 1);
                            // $totalDay = today()->diffInDays($nextExpire);
                            $totalDay = $recharge_day;
                            $action_days_message = 'Total ' . $totalDay . ' days. From ' . $cur . ' To ' . $nextExpire;
                            $subTotalCost = PriceCalculate::calculate(today()->daysInMonth, $subPackage->rate, $totalDay);
                        } else {
                            $nextExpire = Carbon::parse($user->expire_date)->addDays($recharge_day);
                            $totalDay = $nextExpire->diffInDays($user->expire_date) + 0;
                            $action_days_message = 'Total ' . $totalDay . ' days. From ' . $user->expire_date . ' To ' . $nextExpire;
                            $subTotalCost = PriceCalculate::calculate(today()->daysInMonth, $subPackage->rate, $totalDay);
                        }
                    }



                    if ($subTotalCost > $popBalance) {
                        return 'balance_error';
                    }

                    $SubResellerAction = "Recharge For " . $action_days_message . " . For package " . $subPackage->name . " cost BDT " . $subTotalCost;
                    Balance::balanceDeductForUserRecharge('pop', $pop->id, $subTotalCost);

                    if ($subPackage->commission > 0 || globalPermission('commission_from_manager_pop')) {
                        (new CommissionService())->subreseller_commission($subTotalCost, $SubResellerAction, $pop->id, $subPackage->commission, $subPackage->rate, $user->id);
                    }
                    $popBalance_after_recharge  = Balance::getBalance('pop', $pop->id);
                    SubResellerBalanceLogReport::create([
                        'reseller_id'       => $reseller_id,
                        'sub_reseller_id'   => $pop->id,
                        'client_id'         => $id,
                        'action'            => $SubResellerAction,
                        'amount'            => $subTotalCost,
                        'remarks'           => 'Created BY ' . Auth::user()->email,
                        'before_balance'    => $popBalance,
                        'after_balance'    => $popBalance_after_recharge,
                        'reseller_cost' => $totalCost,
                        'commission_amount' => getCommissionForSubResellerRecharge($id, $subTotalCost,),
                        'reseller_balance_log_id' => $resellerBalanceLogReport->id,
                    ]);
                }
            }



            if ($package->commission > 0 || globalPermission('commission_from_manager_pop')) {
                (new CommissionService())->reseller_commission($totalCost, $action, $reseller_id, $package->commission, $package->package_rate, $user->id);
            }

            if ($pop->bill_generate == 'yes') {
                CustomerAccount::updateCustomrAccount($id, $package->package_rate, 0, 0, $totalCost);
                BillGenerateController::entryBillGenerate($id, $totalCost, 'Customer Recharge', 'recharge', $nextExpire);
            }

            $client = Client::with("pop.nas", 'packages')->find($user->id);

            $old_expire_date = $client->expire_date;

            $client->expire_date = $nextExpire;
            $client->billing_cycle = $nextExpire->day;
            if ($nextExpire >= today()) {
                $client->clients_status = 'active';
                Log::info('Dynamic Recharge CID: ' . $user->id . ', New Expire Date: ' . $nextExpire . ', Status: ' . $client->clients_status);
            } else if (checkSettings('expire_billing_change_today_from_billing_date') == 'enable' && $nextExpire == today()->addDay()) {
                $client->clients_status = 'active';
                Log::info('Dynamic Recharge CID: ' . $user->id . ', New Expire Date: ' . $nextExpire . ', Status: ' . $client->clients_status);
            } else {
                $client->clients_status = 'expired';
                Log::info('Dynamic Recharge CID: ' . $user->id . ', New Expire Date: ' . $nextExpire . ', Status: ' . $client->clients_status);

                Log::error(
                    'nextExpire: ' . $nextExpire .
                        ' | Today: ' . today() .
                        ' | expire_billing_change_today_from_billing_date: ' . checkSettings('expire_billing_change_today_from_billing_date') .
                        ' | Next expire == today+1: ' . ($nextExpire == today()->addDay() ? 'true' : 'false') .
                        ' | nextExpire >= today: ' . ($nextExpire >= today() ? 'true' : 'false') .
                        ' | Full condition: ' . (
                            checkSettings('expire_billing_change_today_from_billing_date') == 'enable'
                            && $nextExpire == today()->addDay()
                            ? 'true' : 'false'
                        )
                );
            }

            $client->save();

            $clientCheck = Client::find($client->id);
            Log::info('Dynamic Recharge After Save CID: ' . $user->id . ', Status: ' . $clientCheck->clients_status);

            if (globalPermission('RadiusExpiration')) {

                (new ExpirationService())->handleExpiration($client->userid, $old_expire_date, $client->payment_dadeline, $client->pop->experity_check);
            }

            if (checkAPI()) {
                try {
                    $mk = new SyncWithMk();
                    $mk->syncSingleClient($client->id);
                } catch (\Exception $e) {
                }
            } else {
                (new IdEnableDisableController)->enableInRadius($client);
            }

            return 'success';
        } else {
            Log::error('Dynamic Recharge Error: ' . $user->id . ' has insufficient balance for recharge. Required: ' . $totalCost . ', Available: ' . $resellerBalance . ', Status: ' . $user->clients_status);
            return 'balance_error';
        }
    }

    public function resellerCustomerRechargeSms($successFullIds)
    {

        foreach ($successFullIds as $id) {
            $reseller_recharge = new ResellerRechargeSms();
            $reseller_recharge->send($id);

            $client = Client::with('pop', 'clientsinfo', 'packages')->find($id);
            $reseller_sme_getway = ResellerSmsGetway::with('reseller')->where('reseller_id', $client->pop->reseller_id)->first();
            // dd($reseller_sme_getway);
            if ($reseller_sme_getway) {
                $customer_recharge = collect(json_decode($reseller_sme_getway->sms_formate))->where('sms_type', 'other_reseller_customer_recharge')->first();
                if ($customer_recharge->send_sms == "Yes") {

                    (new ResellerRechargeSms())->sendOtherResellerCustomerRechargeSms(
                        $client,
                        $reseller_sme_getway->sms_gateway,
                        $reseller_sme_getway->reseller->name,
                        $reseller_sme_getway->reseller->contact,
                        $customer_recharge->sms_body,
                        $reseller_sme_getway->reseller->id
                    );
                }
            }
        }
    }
}
