<?php

use Carbon\Carbon;
use App\Models\Nas;
use App\Models\Pop;
use App\Models\User;
use App\Models\Client;
use App\Jobs\SendSmsJob;
use App\Models\Employee;
use App\Models\Packages;
use App\Models\Reseller;
use App\Classes\MikrotikService\Mikrotik;
use App\Classes\MikrotikService\MikrotikStaticIP;
use App\Models\IncomeHead;
use App\Models\SmsSetting;
use App\Models\BillGenerate;
use App\Models\ClientSource;
use App\Models\EmailSetting;
use App\Models\ClientReferer;
use App\Models\GlobalSettings;
use App\Models\LicenseCheckModel;
use App\Models\ResellerSmsGetway;
use App\Models\CompanyInformation;
use App\Http\Controllers\Clients\OnlineCustomerController;
use App\Http\Controllers\CompanyInfoController;
use App\Http\Controllers\OnlinePaymentGetwayTokenController;
use App\Models\Balance;
use App\Models\Clientsinfo;
use App\Models\CRMLog;
use App\Models\NewLineRequest;
use App\Models\OnlinePaymentGetwayToken;
use App\Models\ResellerCommissionReference;
use App\Models\SmsApi;
use App\Services\CommissionCalculationService;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Redis;


function gSettings()
{
    $settings =  cache()->remember('globalSettings', 60 * 60, function () {
        $settings1 = GlobalSettings::get();
        $map = [];
        foreach ($settings1 as $setting) {
            $map[$setting->name] = $setting->status;
        }
        return $map;
    });
    return $settings;
}

function permissions()
{
    return auth()->user()->getAllPermissions()->pluck('name')->toArray();
}

function checkSettings($key)
{
    $query = gSettings();
    return isset($query[$key]) ? $query[$key] : 'disable';
}

// this function will return true if permission given to that setting.
function globalPermission($permissionName)
{
    return checkSettings($permissionName) == "enable";
}


function getSmsMessage()
{
    $message =  cache()->remember('smsMessage', 60 * 60, function () {
        return SmsSetting::select('id', 'tamplate_name', 'tamplate_body')->get();
    });

    return $message;
}

function emailSetting()
{
    $emailSetting =  cache()->remember('emailSetting', 60 * 60, function () {
        return EmailSetting::select('id', 'tamplate_name', 'email_body')->get();
    });
    return $emailSetting;
}

function marketedBy($id = null)
{
    $ref = cache()->remember('referer', 60, function () {
        return ClientReferer::where('status', 'active')->get();
    });

    if ($id) {
        $ref = $ref->where('id', $id)->first();

        return $ref->firstname . ' ' . $ref->lastname;
    } else {
        return $ref;
    }
}

function clientSource($id = null)
{
    $src = cache()->remember('source', 60, function () {
        return ClientSource::get();
    });

    if ($id) {

        $src = $src->where('id', $id)->first();
        return $src->name;
    } else {

        return $src;
    }
}

function checkSmsStatus($info)
{
    $data = json_decode($info);

    if (isset($data->smsinfo)) {
        if ($data->error_message != "") {
            return $data->error_message;
        }
        return $data->smsinfo[0]->reference_id;
    }
    if (isset($data->status)) {
        if ($data->status == "FAILED") {
            return $data->error_message;
        } else {
            return "<span class='text-danger text-bold'>" . smsErrorCode()[$data->status] . "</span>";
        }
    } else {
        return $info;
    }
}

function smsErrorCode()
{
    return [
        '5201' => 'API not valid.',
        '5202' => 'API not Active.',
        '5203' => 'Sender Id not valid.',
        '5204' => 'Test Body not valid.',
        '5205' => 'Contact Numbers Not Valid.',
        '5206' => 'Insuficient Balance.',
        '5207' => 'Insuficient Balance of your seller (The person opned your account).',
        '5208' => 'Account Not Active.',
        '5209' => 'Account Expired.',
        'ok'   => 'SMS Sent',
        'Success'   => 'SMS Sent',
        'You can send sms to only one number at a time for now. This API will support batch shoot very soon. Thank you for your understanding' => 'You can send sms to only one number at a time for now. This API will support batch shoot very soon. Thank you for your understanding'
    ];
}


function checkAPI()
{
    return siteinfo()->mikrotik_conection_type == 'api';
}

function userPackages()
{
    $ids = array_unique(userResellers()->map(function ($reseller) {
        return explode(',', $reseller->package_list);
    })->flatten()->toArray());

    $packages =  Packages::select('id', 'package_name')
        ->whereIn('id', $ids)
        ->orderBy('package_name', 'asc')
        ->get();
    return $packages;
}


function ignoreMKClientList()
{
    return cache()->remember("ignoreMKCheckList", 60 * 60, function () {
        return Client::where("ignoreMKCheck", 1)->pluck("userid")->toArray();
    });
}
function secretFromRedis($userid)
{

    $redis = Redis::get("secret:" . $userid);
    if ($redis) {
        return json_decode($redis, true);
    }
    return null;
}
function activeFromRedis($userid)
{
    $redis = Redis::get("active:" . $userid);
    if ($redis) {
        return json_decode($redis, true);
    }
    return null;
}

function mikrotikOnlineAndOfflineUsers()
{
    $company_information = CompanyInformation::latest()->first();
    $sync_time = $company_information->sync_time_in_secconds ? $company_information->sync_time_in_secconds : 300;
    return cache()->remember("mkUsers", (int)$sync_time, function () {
        $allNas = Nas::all();
        $allOnlineUsers = [];
        $allUsersInMK = [];
        $ipArpListsGlobal = [];
        $allOnlineUsersWithoutMap = [];
        if (globalPermission("clientManageThroughNodeJs")) {
            // Get all active user keys from Redis
            $activeKeys = Redis::keys("active:*");
            $secretKeys = Redis::keys("secret:*");
            // Fetch all active users
            foreach ($activeKeys as $key) {
                $userId = preg_replace('/^[^:]+:/', '', $key);
                $userData = Redis::get($userId);
                if ($userData) {
                    $user = json_decode($userData, true);
                    if ($user && isset($user['name'])) {
                        $allOnlineUsers[$user['name']] = $user;
                        $allOnlineUsersWithoutMap[] = $user;
                    }
                }
            }

            // Fetch all secret users
            foreach ($secretKeys as $key) {
                $userId = preg_replace('/^[^:]+:/', '', $key);
                $userData = Redis::get($userId);
                if ($userData) {
                    $user = json_decode($userData, true);
                    if ($user && isset($user['name'])) {
                        $allUsersInMK[$user['name']] = $user;
                    }
                }
            }
        } else
            foreach ($allNas as $nas) {
                try {
                    $mkIp = $nas->nasname;
                    $mkUser = $nas->mikrotick_user ?? ".";
                    $mkPass = $nas->mikrotick_user_password ?? ".";
                    $mkPort = $nas->mikrotick_port;
                    $mk = new Mikrotik($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
                    $activeUsers = $mk->getActiveConnection();
                    $allUsers = $mk->getSecret();

                    $allOnlineUsersWithoutMap = array_merge($allOnlineUsersWithoutMap, $activeUsers);

                    if (globalPermission("static_ip_manage")) {
                        $mkStatic = new MikrotikStaticIP($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
                        $ipArpLists = $mkStatic->getArpList();
                        foreach ($ipArpLists as $ipArp) {
                            try {
                                $ipArpListsGlobal[$ipArp["address"]] = $ipArp;
                            } catch (\Throwable $th) {
                            }
                        }
                    }

                    foreach ($activeUsers as $user) {
                        $allOnlineUsers[$user["name"]] = $user;
                    }

                    foreach ($allUsers as $user) {
                        $allUsersInMK[$user["name"]] = $user;
                    }
                } catch (Exception $err) {
                    continue;
                }
            }

        return [
            "allUsers" => $allUsersInMK,
            "onlineUsers" => $allOnlineUsers,
            "ipArpListsGlobal" => $ipArpListsGlobal,
            "allOnlineUsersWithoutMap" => $allOnlineUsersWithoutMap
        ];
    });
}

function siteinfo()
{
    $data = cache()->remember('companyinfo', 60 * 60, function () {
        return CompanyInformation::first();
    });
    return $data;
}

function siteLicenseInfo()
{
    $data = cache()->remember('clientLicenseCheck', 60, function () {
        $settings = json_decode(siteinfo()->settings, true);
        return collect($settings)->firstWhere('type', 'customer_panel_api')['value']['client_license_check'] ?? null;
    });

    return $data;
}

function managerBalance()
{
    $user = auth()->user();
    if ($user->hasRole(['Reseller Admin', 'Reseller'])) {
        $resellerId =  DB::table('reseller_user')->where('user_id', $user->id)->pluck('reseller_id')->toArray();
        $balance = Balance::where('type', 'reseller')->where('type_id', $resellerId)->first();
        return $balance->amount ?? 0;
    } else if ($user->hasRole('Admin')) {
        $manager = Reseller::where('reseller_type', 'own')->pluck('id')->toArray();
        $balance = Balance::where('type', 'reseller')->whereIn('type_id', $manager)->sum('amount');
        return $balance ?? 0;
    }
}

function managerCommission()
{
    $user = auth()->user();
    if ($user->hasRole(['Reseller Admin', 'Reseller'])) {
        $resellerId =  DB::table('reseller_user')->where('user_id', $user->id)->pluck('reseller_id')->toArray();
        $accounts = ResellerCommissionReference::selectRaw('sum(received_amount) as ramount, sum(paid_amount) as pamount,reseller_id')->groupBy('reseller_id')->get();

        foreach ($accounts as $ac) {
            if (in_array($ac->reseller_id, $resellerId)) {
                $balance = $ac->ramount - $ac->pamount;
            }
        }

        return $balance ?? 0;
    }
}

function resellerPerDayCost()
{
    $user = auth()->user();
    $resellerId =  DB::table('reseller_user')->where('user_id', $user->id)->pluck('reseller_id')->toArray();
    $pop = Pop::where('reseller_id', $resellerId)->pluck('id')->toArray();
    $client = Client::list()->whereIn('pop_id', $pop)->get();
    $monthly_cost = 0;
    foreach ($client as $key => $value) {
        $monthly_cost += $value->packages->package_rate ?? 0;
    }
    $perdayCost = ($monthly_cost / 30);

    return round($perdayCost ?? 0, 2);
}

function license()
{
    $time = config('app.license_check_time') ?? 60 * 60;

    $last_license_check = cache()->remember('last_license_check', $time, function () {
        return LicenseCheckModel::orderBy('created_at', 'desc')->first();
    });
    return $last_license_check;
}


function license_check()
{
    // if (config('app.license_check')) {
    if (siteLicenseInfo() == "true" || config('app.license_check') == true) {

        $license = license();

        if ($license == null) {
            $info = ['client_type' => '', 'license_check' => ''];
            $total_due = '';
            $exp_date = '';
            $portal_api = customer_panel_api();
            $pay_url = $portal_api->customer_panel_url . '/customer-invoice/' . $portal_api->customer_panel_secret;
        } else {
            $info = collect(json_decode($license->license_check));
            $total_due = collect($info['invoices'])->sum('amount');
            $exp_date = collect($info['invoices'])->first();
            $portal_api         = customer_panel_api();
            $pay_url            = $portal_api->customer_panel_url . '/customer-invoice/' . $portal_api->customer_panel_secret;
        }

        return [
            'total_due' => $total_due ?? 0,
            'info' => $info,
            'pay_url' => $pay_url,
            'exp_date' => $exp_date
        ];
    } else {
        return [
            'total_due' => 0,
            'info' => [],
            'pay_url' => '',
            'exp_date' => ''
        ];
    }
}

function getBillingType()
{
    $billing_type = collect(json_decode(siteinfo()->settings))->where('type', 'billing_type')->first();

    if ($billing_type) {
        return $billing_type->value;
    } else {
        return 'monthly';
    }
}

function customer_panel_api()
{
    $customer_panel_api = collect(json_decode(siteinfo()->settings))->where('type', 'customer_panel_api')->first();

    if ($customer_panel_api) {
        return $customer_panel_api->value;
    } else {
        return '';
    }
}

function client_counter()
{
    return Client::list()->groupBy('clients_status')->selectRaw('clients_status,count(*) as total')->get()->flatten();
}

function totalClientCount()
{
    $clientCount = Client::whereNull('deleted_at')->selectRaw('count(*) as total')->first()->total;
    return $clientCount;
}

function checkRequired($type, $val)
{
    if (checkSettings($type) == 'enable') {
        return $val;
    }
}
function employee_list()
{
    return cache()->remember('employee_list', 60 * 60, function () {
        return Employee::all();
    });
}
function user_list()
{
    return cache()->remember('user_list', 60 * 60, function () {
        return User::all();
    });
}

function user_name($id)
{
    return user_list()->where('id', $id)->first()->name ?? '';
}
function employee_name($id)
{
    return employee_list()->where('id', $id)->first()->name ?? '';
}

function user_email($id)
{
    if ($id == 1) {
        return "";
    }
    return user_list()->where('id', $id)->first()->email ?? '';
}

function clearCache($type)
{
    foreach (user_list() as $u) {
        cache()->forget($type . '_' . $u->id);
    }

    cache()->forget($type);
}

function userPermissions()
{
    return  auth()->user()->getAllPermissions()->pluck('name')->toArray();
}


function userPops()
{
    return Pop::list();
}
function userResellers()
{
    return Reseller::list();
}

function clientStatusClass($status)
{
    if ($status == 'expired') {
        return 'deactive bg-danger';
    } elseif ($status == 'deactive') {
        return 'bg-secondary';
    } elseif ($status == 'disable') {
        return 'bg-warning';
    } elseif ($status == 'active') {
        return 'bg-success';
    }
}


function employees()
{

    $data = cache()->remember('employees', 60 * 60, function () {
        // dd("conme");
        return Employee::where('status', 'active')->orderBy('name', 'asc')->get();
    });
    // dd("not come");
    return $data;
}

function imcomeHead()
{
    $data = cache()->remember('incomeHead', 60 * 60, function () {
        return IncomeHead::all();
    });
    return $data;
}

function getResellerSmsGateway($client)
{
    $resellerId = $client->pop->reseller_id ?? null;

    if (!$resellerId) {
        return null; // or handle the missing ID gracefully
    }

    return ResellerSmsGetway::with('reseller')
        ->where('reseller_id', $resellerId)
        ->first();
}




if (!function_exists('sendSmsAfterExtended')) {
    function sendSmsAfterExtended($client_id, $new_extended_date)
    {
        $company_info = CompanyInformation::latest()->first();
        $sms_setting = json_decode(getSmsMessage()->where('tamplate_name', 'temporary_extended')->first()->tamplate_body, true);
        // dd($sms_setting);
        $sms_send = $sms_setting["sendsms"];
        $message = $sms_setting["sms_body"];
        $client = Client::with('clientsinfo', 'customerAccount')->find($client_id);
        $new_date = Carbon::parse($client->expire_date)->addDay($new_extended_date)->format('d-M-Y');
        if ($sms_send == "Yes") {
            $actual_message = str_replace("{c_id}", "{$client->id}", $message);
            $actual_message = str_replace("{c_code}", "{$client->customer_code}", $actual_message);
            $actual_message = str_replace("{c_password}", "{$client->password}", $actual_message);
            $actual_message = str_replace("{c_username}", "{$client->userid}", $actual_message);
            $actual_message = str_replace("{c_name}", "{$client->clientsinfo->clients_name}", $actual_message);
            $actual_message = str_replace("{c_deadline}", "{$client->expire_date}", $actual_message);
            $actual_message = str_replace("{TotalDue}", "{$client->customerAccount->dueAmount}", $actual_message);
            $actual_message = str_replace("{company_name}", "{$company_info->name}", $actual_message);
            $actual_message = str_replace("{company_cell}", "{$company_info->mobile}", $actual_message);
            $actual_message = str_replace("{new_billing_date}", "{$new_date}", $actual_message);

            $data = [
                'message' => $actual_message,
                'contact_no' => $client->clientsinfo->contact_no,
                'type' => 'extended_day'
            ];

            SendSmsJob::dispatch($data);
        }
    }
}

if (!function_exists('sendSmsAfterBillgenerate')) {
    function sendSmsAfterBillgenerate($bill_generates_id)
    {
        $link = CompanyInfoController::baseUrl();
        $sms_setting = json_decode(getSmsMessage()->where('tamplate_name', 'bill_generate')->first()->tamplate_body, true);
        // $result_decode = json_decode($sms_setting->tamplate_body, true);
        $sms_send = $sms_setting["sendsms"];
        $message = $sms_setting["sms_body"];
        $now = new \DateTime('now');
        $current_month = $now->format('M-Y');
        // dd($sms_send);
        $company_info = CompanyInformation::latest()->first();
        $bill = BillGenerate::with('clients.customerAccount', 'clientsinfo')->find($bill_generates_id);
        $dead_line_time = Carbon::parse($bill->clients->expire_date)->addDay($bill->clients->payment_dadeline)->format('d-M-Y');
        // If billgenerate send sms == yes than proceed
        if ($sms_send == "Yes") {

            $actual_message = str_replace("{c_name}", "{$bill->clientsinfo->clients_name}", $message);
            $actual_message = str_replace("{c_username}", "{$bill->clients->userid}", $actual_message);
            $actual_message = str_replace("{MonthBillAmount}", "{$bill->bill_amount}", $actual_message);
            $actual_message = str_replace("{ThisMonth}", "-{$current_month}", $actual_message);
            $actual_message = str_replace("{company_name}", "{$company_info->name}", $actual_message);
            $actual_message = str_replace("{company_cell}", "{$company_info->mobile}", $actual_message);
            $actual_message = str_replace("{c_id}", "{$bill->clients->id}", $actual_message);
            $actual_message = str_replace("{TotalDue}", "{$bill->clients->customerAccount->dueAmount}", $actual_message);
            $actual_message = str_replace("{billing_deadline}", "{$dead_line_time}", $actual_message);
            $actual_message = str_replace("{MonthDiscountAmount}", "{$bill->clients->billing_cycle}", $actual_message);
            $actual_message = str_replace("{bill_type}", "{$bill->billing_type}", $actual_message);
            $actual_message = str_replace("{expireDate}", "{$bill->clients->expire_date}", $actual_message);
            $actual_message = str_replace("{payment_url}", $link . $bill->clients->slug, $actual_message);
            $data = [
                'message' => $actual_message,
                'contact_no' => $bill->clientsinfo->contact_no,
                'type' => 'bill_generate'
            ];



            SendSmsJob::dispatch($data);
        }
    }
}

if (!function_exists('sendSmsAfterExpired')) {
    function sendSmsAfterExpired($client_id)
    {
        $link = CompanyInfoController::baseUrl();
        $sms_setting = json_decode(getSmsMessage()->where('tamplate_name', 'expired')->first()->tamplate_body, true);

        $sms_send = $sms_setting["sendsms"];
        $message = $sms_setting["sms_body"];


        $company_info = CompanyInformation::latest()->first();
        $client = Client::with('customerAccount', 'packages')->find($client_id);
        $new_date = Carbon::parse($client->expire_date)->addDay($client->payment_dadeline)->format('d-M-Y');

        if ($sms_send == "Yes") {
            $message = str_replace(
                [
                    '{c_id}',
                    '{c_code}',
                    '{c_username}',
                    '{c_password}',
                    '{c_name}',
                    '{c_deadline}',
                    '{TotalDue}',
                    '{company_name}',
                    '{company_cell}',
                    '{new_billing_date}',
                    '{payment_url}',
                    '{monthly_bill}'
                ],
                [
                    $client->id,
                    $client->customer_code,
                    $client->userid,
                    $client->password,
                    $client->clientsinfo->clients_name,
                    $client->expire_date,
                    $client->customerAccount->dueAmount ?? 0,
                    $company_info->name,
                    $company_info->mobile,
                    $new_date,
                    $link . $client->slug,
                    $client->packages->package_rate ?? 0,
                ],
                $message
            );


            $data = [
                'message' => $message,
                'contact_no' => $client->clientsinfo->contact_no,
                'type' => 'expired'
            ];

            // check if d2dy and customer has advance balance then don't send sms
            $clientBalance = $client->customerAccount->dueAmount ?? 0;
            $clientPackageRate = $client->packages->package_rate ?? 0;
            $clientPermanentDiscount = $client->parmanent_discount ?? 0;

            $total_due = ($clientPackageRate + $clientBalance) - $clientPermanentDiscount;


            if (getBillingType() == 'day_to_day' && $total_due <= 0) {
                return;
            }

            SendSmsJob::dispatch($data);
        }
    }
}


if (!function_exists('totalOnlineCustomer')) {
    function totalOnlineCustomer()
    {
        if (checkAPI()) {
            if (globalPermission("clientManageThroughNodeJs")) {
                $activeKeys = Redis::keys("active:*");

                $usernames = array_map(function ($key) {
                    return substr(strrchr($key, ':'), 1);
                }, $activeKeys);

                return Client::list()->whereIn("userid", $usernames)->count();
            } else {
                $allMikrotik = Nas::all();
                $count = 0;
                $countDuplicateClient = [];
                $allMikrotikAndActiveUsers = [];
                // MikroTik-based logic
                foreach ($allMikrotik as $mikrotik) {
                    try {
                        $mkIp = $mikrotik->nasname;
                        $mkUsername = $mikrotik->mikrotick_user;
                        $mkPassword = $mikrotik->mikrotick_user_password;
                        $mkPort = $mikrotik->mikrotick_port;
                        $mk = new Mikrotik($mkIp, $mkUsername, $mkPassword, $mkPort ? (int)$mkPort : 8728);
                        $allActiveUsers = $mk->getActiveConnection();

                        $mikrotikAndActiveUsers = [
                            "nasIp" => $mkIp,
                            "activeUsers" => []
                        ];

                        $currentActiveUsers = [];
                        foreach ($allActiveUsers as $user) {
                            $currentActiveUsers[$user["name"]] = $user;
                        }

                        $clients = Client::list()->whereIn("userid", array_keys($currentActiveUsers))->get();

                        foreach ($clients as $client) {
                            if (
                                array_key_exists($client->userid, $currentActiveUsers) &&
                                !array_key_exists($client->userid, $countDuplicateClient)
                            ) {
                                array_push($mikrotikAndActiveUsers["activeUsers"], $currentActiveUsers[$client->userid]);
                                $countDuplicateClient[$client->userid] = 1;
                                $count++;
                            }
                        }

                        array_push($allMikrotikAndActiveUsers, $mikrotikAndActiveUsers);
                    } catch (Exception $err) {
                        Log::error("Error in totalOnlineCustomer: " . $err->getMessage() . " in " . $mikrotik->nasname);
                        continue;
                    }
                }

                return $count;
            }
        } else {
            return (new OnlineCustomerController)->online_customer_list() ?? 0;
        }
    }
}


function dateTimeDifferent($dateTime1, $dateTime2)
{
    return  Carbon::parse($dateTime1)->diff($dateTime2)->format('%d days, %h hours and %i minutes');
}

function array_find($xs, $f)
{
    foreach ($xs as $x) {
        if (call_user_func($f, $x) === true)
            return $x;
    }
    return null;
}

function getStaticIpFromBlock($ip_block)
{
    if (!$ip_block) return [];

    // Split the IP block into the base IP address and the subnet prefix length
    list($base_ip, $subnet_prefix_length) = explode('/', $ip_block);
    $base_ip_parts = explode('.', $base_ip);

    // Calculate the number of IP addresses in the range
    $num_addresses = pow(2, (32 - (int)$subnet_prefix_length));

    // Convert the base IP address to an integer for easier manipulation
    $base_ip_int = ($base_ip_parts[0] << 24) + ($base_ip_parts[1] << 16) + ($base_ip_parts[2] << 8) + $base_ip_parts[3];

    // Calculate the starting and ending IP address in integer form
    $start_ip_int = $base_ip_int + 2;
    $end_ip_int = $base_ip_int + $num_addresses - 2;

    // Convert the integer IP addresses back to dotted decimal notation
    $ip_range = array();
    for ($ip_int = $start_ip_int; $ip_int <= $end_ip_int; $ip_int++) {
        $ip_parts = array(
            ($ip_int >> 24) & 255,
            ($ip_int >> 16) & 255,
            ($ip_int >> 8) & 255,
            $ip_int & 255
        );
        $ip_address = implode('.', $ip_parts);
        $ip_range[] = $ip_address;
    }

    return $ip_range;
}

function getTotalOtc($id)
{
    $otcBill_generate = BillGenerate::where('client_id', $id)->where('billing_type', '==', 'otc')->get();
    $total_otc = 0;
    $total_paid = 0;
    if ($otcBill_generate->count() > 0) {
        $total_otc = $otcBill_generate->sum('bill_amount');
        $total_paid = $otcBill_generate->sum('paid_amount');
    }

    $data = [
        'total_otc' => $total_otc,
        'otc_due' => $total_otc - $total_paid,
    ];

    return $data;
}

function get_reseller_name($id)
{
    $reseller = Reseller::find($id);
    return $reseller->name ?? '';
}

function get_pop_name($id)
{
    $pop = Pop::find($id);
    return $pop->popname ?? '';
}

function get_client_name($id)
{
    $clients_info = Clientsinfo::where('client_id', $id)->first();
    return $clients_info->clients_name ?? '';
}

function get_name($id, $table_name)
{
    if ($table_name == 'Reseller') {
        return get_reseller_name($id);
    } elseif ($table_name == 'Pop') {
        return get_pop_name($id);
    } elseif ($table_name == 'Client') {
        return get_client_name($id);
    }
}

function crm_client_counter()
{


    $popIds = userPops()->pluck('id');

    $clients = DB::table('clients')
        ->where('deleted_at', null)
        ->whereIn('pop_id', $popIds)
        ->where('clients_status', '!=', 'active')
        ->where('clients_status', '!=', 'disable')
        ->select('crm_status', DB::raw('COUNT(*) as total'))
        ->groupBy('crm_status')
        ->get()->flatten();

    return $clients;
}

function checkCrmRansferPermission($url)
{

    if (checkSettings('CRM') != 'enable') {

        return false;
    }
    if (
        $url == 'admin/crm-clients' || $url == 'admin/crm-list/Marketing' || $url == 'admin/crm-list/CRM'
        || $url == 'admin/crm-list/Support' || $url == 'admin/crm-list/Account' || $url == 'admin/crm-list/Fiber'
        || $url == 'admin/crm-list/Store' || $url == 'admin/crm_customer_search' || $url == 'admin/list/close-list'
        || $url == 'admin/close-search-list'
    ) {
        return true;
    }
}


function techno_bulk_sms($ap_key, $user_email)
{
    $url = 'https://24bulksms.com/24bulksms/api/user-info-chack';
    $data = array(
        'api_key' => $ap_key,
        'user_email' => $user_email
    );
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    $output = curl_exec($curl);
    curl_close($curl);
    return $output;
}

function getYourSmsBalance()
{
    $result =  cache()->remember('smsapi', 60 * 60, function () {
        return SmsApi::where('status', 'enable')->first();
    });

    try {

        if ($result) {
            $host = parse_url($result->balance_url);
            if ($host['host'] == 'smsplus.sslwireless.com') {
                $res = Http::post($result->balance_url, [
                    'api_token' => $result->apikey,
                    'sid' => $result->sender,
                ]);
                $b = json_decode($res->body());
                $balance = $b->balance;
            } else if ($host == 'sms.solutionsclan.com') {
                $res = Http::get($result->path);
                $b = json_decode($res->body());
                $balance = $b->balance;
            } else if ($host['host'] == '24bulksms.com') {
                $email = $result->sender;
                $ap_key = $result->apikey;
                $res = techno_bulk_sms($ap_key, $email);
                $b = json_decode($res);
                $balance = $b->data->balance;
            } else if ($host['host'] == 'smpp.revesms.com') {

                $res = Http::get($result->balance_url);

                $balance = json_decode($res)->Balance;
            } else {
                $res = Http::get($result->path);
                $balance =  $res->body();
            }
        } else {

            $balance = 0;
        }
    } catch (\Throwable $th) {
        $balance = 0;
    }

    return $balance;
}

function getLastCRMDate($client_id)
{
    $crm_log = CRMLog::where('client_id', $client_id)->orderBy('created_at', 'desc')->first();
    if ($crm_log) {
        return  $crm_log->crm_check_date;
    } else {
        return "";
    }
}


function parseDate($dateString)
{
    $formats = ['M/d/Y H:i:s', 'Y-m-d H:i:s'];

    foreach ($formats as $format) {
        try {
            $parsedDate = Carbon::createFromFormat($format, $dateString);
            if ($parsedDate !== false && $parsedDate->isValid()) {
                return $parsedDate->format('d/M/Y h:i:s A');
            }
        } catch (\Throwable $th) {
        }
    }

    return $dateString;
}

function getdaytod2d()
{
    $billing_type = collect(json_decode(siteinfo()->settings))->where('type', 'billing_type')->first();

    if ($billing_type) {
        return $billing_type->value;
    } else {
        return 'monthly';
    }
}

function createUUID()
{
    $id = Str::uuid();

    return $id;
}
function checkSmsBalance($resellerId)
{
    $resellerGateway = ResellerSmsGetway::where('reseller_id', $resellerId)->first();

    if (!$resellerGateway || !$resellerGateway->sms_balance_url) {
        return [
            'status'  => 'FAILED',
            'balance' => number_format(0, 2)
        ];
    }

    try {
        $balanceUrlData = $resellerGateway->sms_balance_url;
        $splitData = explode(';', $balanceUrlData);

        // Case: simple URL (no semicolon-separated params)
        if (count($splitData) < 2) {
            $urlParts = parse_url($resellerGateway->sms_balance_url);
            $url = $urlParts['scheme'] . '://' . $urlParts['host'] . $urlParts['path']
                . (isset($urlParts['query']) ? '?' . $urlParts['query'] : '');

            $res = Http::timeout(10)->get($url);
            return [
                'status'  => 'Success',
                'balance' => $res->body()
            ];
        }

        // Extract data for advanced API gateways
        $balanceUrl = $splitData[0];
        $apiKey     = $splitData[1] ?? '';
        $senderId   = $splitData[2] ?? '';
        $urlParts   = parse_url($balanceUrl);
        $host       = $urlParts['host'] ?? '';

        $balance = 0;
        $status  = 'FAILED';

        if ($host === 'smsplus.sslwireless.com') {
            $res = Http::timeout(10)->post($balanceUrl, [
                'api_token' => $apiKey,
                'sid'       => $senderId,
            ]);
            $response = json_decode($res->body());
            if (!empty($response) && $response->status !== 'FAILED') {
                $balance = $response->balance ?? 0;
                $status  = 'Success';
            } else {
                $status = $response->error_message ?? 'FAILED';
            }
        } elseif ($host === 'sms.solutionsclan.com') {
            $res = Http::timeout(10)->get($balanceUrl);
            $response = json_decode($res->body());
            $balance = $response->balance ?? 0;
            $status  = 'Success';
        } elseif ($host === '24bulksms.com') {
            $res = techno_bulk_sms($apiKey, $senderId);
            $response = json_decode($res);
            $balance = $response->data->balance ?? 0;
            $status  = 'Success';
        } elseif ($host === 'smpp.revesms.com') {
            $res = Http::timeout(10)->get($balanceUrl);
            $response = json_decode($res->body());
            if ($response && isset($response->Balance)) {
                $balance = $response->Balance;
                $status  = 'Success';
            }
        } else {
            // Default: try GET request and use raw response
            $res = Http::timeout(10)->get($balanceUrl);
            $balance = $res->body();
            $status  = 'Success';
        }

        return [
            'status'  => $status,
            'balance' => number_format((float)$balance, 2)
        ];
    } catch (\Throwable $e) {


        return [
            'status'  => 'FAILED',
            'balance' => number_format(0, 2)
        ];
    }
}



function getResellerClientPaymentAmount($client)
{

    if (globalPermission('setClientPaymentAmountToClient')) {
        return $client->client_payment_amount;
    }

    if ($client->pops->subreseller === 'yes') {
        return $client->subpack->client_payment_amount ?? 0;
    }

    return $client->packages->client_payment_amount;
}


function getDueAmount($client)
{
    $parmanentDiscount = $client->parmanent_discount ?? 0;
    if (globalPermission('setPackagePriceAsDueAmountForPayBill')) {
        $end = Carbon::parse(now()->endOfMonth())->format('Y-m-d');
        $clientExpireDate = Carbon::parse($client->expire_date)->format('Y-m-d');

        // Check if expire date is smaller than $end
        if ($clientExpireDate <= $end) {

            if (($client->customerAccount->dueAmount < 0) && abs($client->customerAccount->dueAmount) >= ($client->packages->package_rate - $parmanentDiscount)) {

                return  0.0;
            }
            // dd("comes");
            $dueAmount = (isset($client->customerAccount) ? $client->customerAccount->dueAmount : 0) + $client->packages->package_rate - $parmanentDiscount;
            return $dueAmount > 0.0 ? $dueAmount : 0.0;
        }

        return (isset($client->customerAccount) ? $client->customerAccount->dueAmount : 0);
    }

    $dueAmount = isset($client->customerAccount) ? $client->customerAccount->dueAmount : 0;
    return $dueAmount > 0.0 ? $dueAmount : 0.0;
}

function getCommissionForResellerRecharge($clientId, $amount)
{
    $client = Client::with('packages', 'pop')->find($clientId);

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

        if (globalPermission('commission_from_manager_pop')) {
            $thisResellerCommission = Reseller::find($client->pop->reseller_id);
            $commission = (new CommissionCalculationService())->calculateCommission(100, $thisResellerCommission->commission_percentage, $amount);
            return $commission;
        } else {
            $commission = (new CommissionCalculationService())->calculateCommission($client->packages->package_rate, $client->packages->commission, $amount);
            return $commission;
        }
    }

    return 0;
}

function getCommissionForSubResellerRecharge($clientId, $amount)
{
    $client = Client::with('subpack')->find($clientId);

    if (isset($client->subpack) && isset($client->subpack->commission) && $client->subpack->commission > 0) {
        $commission = (new CommissionCalculationService())->calculateCommission($client->subpack->rate, $client->subpack->commission, $amount);
        return $commission;
    }

    return 0;
}

function getEmployesInExpense()
{
    if (auth()->user()->hasPermissionTo('can-not-change-employee-in-expense')) {
        $employes = Employee::where('admin_user_id', auth()->user()->id)->get();
    } else {
        $employes = Employee::where('status', 'active')->get();
    }

    return $employes;
}

function subManagerBalance()
{
    $user = auth()->user();
    if ($user->hasRole(['Sub Reseller'])) {
        $subResellerId =  DB::table('pop_user')->where('user_id', $user->id)->pluck('pop_id')->toArray();
        $balance = Balance::where('type', 'pop')->where('type_id', $subResellerId)->first();
        return $balance->amount ?? 0;
    }
}

function getAllMonthAndYearOfBillGenerate()
{
    $yearMonths =  DB::select("SELECT DISTINCT
                                DATE_FORMAT(created_at, '%Y-%M') AS year
                            FROM
                                bill_generates
                            ORDER BY year DESC;");

    return $yearMonths;
}

function darkMode()
{
    if (isset($_COOKIE['darkMode'])) {
        $darkMode = $_COOKIE['darkMode'];

        return $darkMode === 'enabled'; // Return true if dark mode is enabled
    }
    return false; // Default to false if the cookie is not set
}

function formatUptime($uptime)
{
    return preg_replace('/(\d+)h(\d+)m(\d+)s/', '$1:$2:$3', $uptime);
}

function getTokenForBkash()
{
    // Get existing token record
    $record = OnlinePaymentGetwayToken::where('payment_gateway', 'bkash')->first();

    // If no record found, create token immediately
    if (!$record) {
        (new OnlinePaymentGetwayTokenController())->storeToken();
        return OnlinePaymentGetwayToken::where('payment_gateway', 'bkash')->value('token') ?? '';
    }

    // Calculate age of token
    $minutes = now()->diffInMinutes($record->updated_at);

    // If older than 55 minutes → refresh token
    if ($minutes > 55) {
        (new OnlinePaymentGetwayTokenController())->storeToken();
        return OnlinePaymentGetwayToken::where('payment_gateway', 'bkash')->value('token') ?? '';
    }

    // Token is still valid → return old token
    return $record->token ?? '';
}


function newClientRequestCount()
{
    $count = NewLineRequest::where('status', 'pending')->count();
    return $count;
}

function getManagerPopFromUserId($userId)
{
    $client = Client::with(['pop.reseller'])->where('userid', $userId)->first();

    if (!$client || !$client->pop) {
        return '';
    }

    $popName = $client->pop->popname ?? '';
    $resellerName = $client->pop->reseller->name ?? '';

    return trim("{$popName} ({$resellerName})");
}
