<?php

namespace App\Http\Controllers;

use App\Classes\Accounting\Accounting;
use MyEvent;

use Exception;
use Carbon\Carbon;
use Pusher\Pusher;
use App\Models\Box;
use App\Models\Nas;
use App\Models\Pop;
use \RouterOS\Query;
use App\Services\Sms;
use App\Models\Client;
use App\Models\Income;
use App\Models\Balance;
use App\Models\Payment;
use App\Models\Upazila;
use App\Jobs\SendSmsJob;
use App\Models\District;
use App\Models\Division;
use App\Models\Employee;
use App\Models\Packages;
use App\Models\Radcheck;
use App\Models\Reseller;
use App\Models\User_log;
use App\Models\RadiusLog;
use App\Rules\UserIdRule;
use App\Models\IncomeHead;
use App\Models\SubPackage;
use App\Events\SecondEvent;
use App\Models\Billpayment;
use App\Models\Clientsinfo;
use Illuminate\Support\Str;
use App\Models\ClientSource;
use App\Models\ResellerArea;
use Illuminate\Http\Request;
use App\Classes\Notification;
use App\Models\ClientEditLog;
use App\Models\ClientReferer;
use App\Services\ExpireCheck;
use App\Exports\ClientsExport;
use App\Imports\ClientsImport;
use App\Models\UserAccounting;
use App\Classes\SMS\WelcomeSms;
use App\Models\CustomerAccount;
use App\Models\CustomerDelInfo;
use App\Exports\AllClientExport;
use App\Exports\ClientExportNew;
use App\Services\ClientServices;
use App\Models\ApiBandwidthUsage;
use App\Models\CompanyInformation;
use App\Services\AuthCheckService;
use Illuminate\Support\Facades\DB;
use App\Models\MikcrotikClientList;
use App\Services\CommissionService;
use Illuminate\Support\Facades\Log;
use App\Http\Controllers\Controller;
use App\Jobs\ClientSyncJobForSingle;
use App\Services\BillingCycleChange;
use Brian2694\Toastr\Facades\Toastr;
use Illuminate\Support\Facades\Auth;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Facades\Cache;
use App\Http\Resources\ClientsResource;
use App\Models\ReselleBalanceLogReport;
use Facade\FlareClient\Stacktrace\File;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Storage;
use App\Exports\ClientsImportSampleFile;
use App\Imports\ClientsImportToCustomer;
use App\Classes\customer\clientLiveSpeed;
use App\Classes\MikrotikService\Mikrotik;
use App\Classes\MikrotikService\SyncWithMk;
use App\Models\SubResellerBalanceLogReport;
use Brian2694\Toastr\Toastr as ToastrToastr;
use App\Services\ClientActiveDeactiveService;
use Facade\Ignition\Support\Packagist\Package;
use App\Classes\MikrotikService\MikrotikStaticIP;
use App\Exports\ClientDueImportSampleFile;
use App\Http\Controllers\SessionRefreshController;
use App\Http\Controllers\Clients\IdDisconnectController;
use App\Http\Controllers\Clients\IdEnableDisableController;
use App\Imports\ClientdueImport;
use App\Models\ClientImportAmountReport;
use App\Models\Thana;
use App\Services\ClientApproveService;
use App\Services\ExpirationService;
use Throwable;
use App\Facades\RadPostAuthFacade;
use App\Models\BillGenerate;
use App\Models\OltOnuInformation;
use App\Rules\NoBangla;
use App\Services\NumberValidation;
use App\Services\RadiusClientSync;
use Illuminate\Support\Facades\Validator;
use Yajra\DataTables\Facades\DataTables;

class ClientController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:mac-customer_index|mac-customer_create|mac-customer_edit|mac-customer_destroy', ['only' => ['index', 'show']]);
        $this->middleware('permission:mac-customer_create', ['only' => ['create', 'store']]);
        $this->middleware('permission:mac-customer_edit', ['only' => ['edit', 'update']]);
        $this->middleware('permission:mac-customer_destroy', ['only' => ['destroy']]);
    }

    protected $billingCycle = [];



    public function index()
    {
        $currentPage = request()->get('page', 1);
        $sortBy = request()->get('sort', 'id');
        $sortOrder = request()->get('order', 'asc');

        // Validate sort parameters - only allow expire_date for now
        $allowedSortFields = ['id', 'expire_date'];
        if (!in_array($sortBy, $allowedSortFields)) {
            $sortBy = 'id';
        }
        if (!in_array($sortOrder, ['asc', 'desc'])) {
            $sortOrder = 'asc';
        }

        $list = Client::list();

        // Apply sorting
        $list = $list->orderBy($sortBy, $sortOrder);

        if (checkSettings('all-client-dataTable') == 'enable') {
            $list = $list->paginate(5000);
        } else {
            $list = $list->paginate(100);
        }

        // Maintain sorting parameters in pagination links
        $list->appends(['sort' => $sortBy, 'order' => $sortOrder]);

        if (checkAPI()) {
            if (!globalPermission("clientManageThroughNodeJs"))
                $online = mikrotikOnlineAndOfflineUsers();
            $online["usersBandwidth"] = [];
            if (checkSettings('showClientUpDownInfo') == 'enable') {
                foreach ($list as $user) {
                    if (array_key_exists($user->userid, $online["onlineUsers"])) {
                        $mikrotick_info = $user->pop->nas;
                        $mk = new Mikrotik($mikrotick_info->nasname, $mikrotick_info->mikrotick_user, $mikrotick_info->mikrotick_user_password, $mikrotick_info->mikrotick_port ? (int)$mikrotick_info->mikrotick_port : 8728);
                        $online["usersBandwidth"][$user->userid] = $mk->getBandwidthUsage($user->userid);
                    }
                }
            }
        } else {
            $online = Client::online($list->pluck('userid'));
        }
        // dd($list->toArray());
        return view('clients.index', [
            'list'       => $list,
            'page_title' => 'Customer List',
            'url' => route('clients.create'),
            'online' => $online,
            'confday' => config('app.billing_cycle'),
            'sortBy' => $sortBy,
            'sortOrder' => $sortOrder,
        ]);
    }

    public function changeExpireDate(Request $request)
    {
        if (!auth()->user()->can('change-expire-date')) {
            return response()->json([
                'message' => 'You are not authorized to do this.',
                'status' => 'error'
            ]);
        }

        // dd(auth()->user()->can('change-expire-date'));

        DB::beginTransaction();
        try {

            $this->validate($request, [
                'client_id' => 'required|exists:clients,id',
                'expire_date' => 'required|date_format:Y-m-d', //|after_or_equal:today',
            ]);

            $client = $logClient = Client::find($request->client_id);
            $old_client_data = Client::with('clientsinfo')->find($logClient->id);
            $old_pop = Pop::find($old_client_data->pop_id);

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

            $condition = false;
            if (globalPermission('expire_before_expire_date')) {
                $time = collect(json_decode(siteinfo()->settings))->where('type', 'expire_time')->first()->value ?? '00:00:00';
                $expireDate = Carbon::parse($request->expire_date)->toDateString();
                $expDateTime = Carbon::parse($expireDate . ' ' . $time);
                $condition = $expDateTime < now();
            } else {
                $condition = Carbon::parse($request->expire_date) < today();
            }
            // if (Carbon::parse(Carbon::parse($request->expire_date)) < today()) {
            if ($condition) {
                $cstatus = 'expired';
                $client->clients_status = 'expired';
            } else {
                $client->clients_status = 'active';
                $cstatus = 'active';
            }
            $client->save();

            $new_client_data = Client::with('clientsinfo')->find($logClient->id);
            $this->clientEditLog($logClient, $old_client_data, $new_client_data);
            if (globalPermission('RadiusExpiration')) {

                (new ExpirationService())->handleExpiration($client->userid, $old_client_data->expire_date, $client->payment_dadeline, $old_pop->experity_check);
            }

            DB::commit();

            ClientSyncJobForSingle::dispatch($client->id);

            (new SyncWithMk())->syncSingleClient($client->id);

            return response()->json([
                'message' => 'Expire Date Changed Successfully. ID will be resync shortly.',
                'status' => 'success',
                'expire_date' => Carbon::parse($request->expire_date)->format('d-M-Y'),
                'cstatus' => $cstatus
            ]);
        } catch (\Throwable $th) {

            DB::rollback();
            return response()->json([
                'message' => $th->getMessage(),
                'status' => 'error'
            ]);
        }
    }



    public function deactivatedClients()
    {
        $list = ClientServices::customerList('deactivated');

        return view('clients.index', [
            'list'       => $list->paginate(10000),
            'page_title' => 'Deactivated Customer List',
        ]);
    }


    public function getPackageIpRange()
    {
        $package = Packages::where('id', request()->package_id)->first();
        $package = $package->profile_name;
        $pop = Pop::where('id', request()->pop_id)->first();
        $popId = $pop->id;
        $nas = Nas::where('id', $pop->nas_id)->first();
        if (checkApi() && checkSettings('static-ip-check') == 'enable') {
            $ip = $this->ipRange($package, $nas, $popId);
        } else {
            $ip = null;
        }

        return $ip;
    }

    public function getBox()
    {
        $box = Box::where('pop_id', request()->pop_id)->get();
        $options = '';
        foreach ($box as $b) {
            $options .= "<option value='" . $b->id . "'>" . $b->box_name . "</option>";
        }
        // dd($options);
        return $options;
    }

    public function getStaticIpRange()
    {
        $pop = Pop::where('id', request()->pop)->first();
        $nas = Nas::where('id', $pop->nas_id)->first();
        $blocks = json_decode($nas->ip_block);
        $ipblock = null;
        foreach ($blocks as $block) {
            if ($block->id == request()->id) {
                $ipblock = $block->ip_block;
            }
        }
        $staticIp = getStaticIpFromBlock($ipblock);

        $client = Client::pluck('ip_address')->all();

        $result = array_diff($staticIp, $client);
        $options = '';

        foreach ($result as $ip) {
            $options .= "<option value=\"$ip\">$ip</option>";
        }
        return $options;
    }

    public function getStaticIp()
    {
        $pop = Pop::where('id', request()->pop_id)->first();
        $nas = Nas::where('id', $pop->nas_id)->first();

        if (isset($nas->ip_block)) {
            $datas = json_decode($nas->ip_block);
        } else {
            $datas = null;
        }

        $ports = [];
        if ($datas != null) {
            foreach ($datas as $data) {
                $ports[] = "<option value=" . $data->id . ">" . $data->port . " - " . $data->ip_block . "</option>";
            }
        }

        return $ports;
    }

    public function ipRange($package, $nas, $popId)
    {
        // dd([$nas]);
        try{
            $mk = new Mikrotik($nas->nasname, $nas->mikrotick_user, $nas->mikrotick_user_password, $nas->mikrotick_port ? (int)$nas->mikrotick_port : 8728);
            $ipRange = $mk->getIpRanges($package);
            $ipBlock = explode(',', $ipRange);

            function generateIPs($range)
            {
                $ips = array();
                $parts = explode('-', $range);
                $start = ip2long(trim($parts[0]));
                $end = ip2long(trim($parts[1]));
                for ($i = $start; $i <= $end; $i++) {
                    $ips[] = long2ip($i);
                }
                return $ips;
            }
            $pop_id = Pop::where('id', $popId)->first();
            $nas_id = $pop_id->nas_id;

            // $pop_ids = Pop::where('nas_id', $nas_id)->pluck('id');
            // $client = Client::whereIn('pop_id', $pop_ids)->pluck('ip_address')->toArray();
            $client = Client::pluck('ip_address')->all();
            // dd($client);

            $options = '';
            foreach ($ipBlock as $range) {
                $ips = generateIPs($range);

                $result = array_diff($ips, $client);

                foreach ($result as $ip) {
                    if (Client::where('ip_address', $ip)) {
                        $options .= "<option value=\"$ip\">$ip</option>";
                    }
                }
            }
            // dd($options);
            return $options;
        } catch (Exception $err) {
            Toastr::error($err->getMessage(), 'Error');
        }
    }

    public function getResellerArea(Request $request)
    {
        if (request()->ajax() && !empty($request->id)) {

            $id = auth()->id();
            if (auth()->user()->hasRole(['Sub Reseller'])) {

                $pop_id = DB::table('pop_user')->where('user_id', $id)->pluck('pop_id')->toArray();
                $pop = ResellerArea::where('pop_id', $pop_id)->get();
            } else {

                $reseller = Pop::where('id', $request->id)->first();
                $pop = ResellerArea::where('reseller_id', $reseller->reseller_id)->get();
            }
            $option = '<option value="">Select One</option>';

            foreach ($pop as $p) {
                $option .= "<option value='" . $p->area . "'>" . $p->area . "</option>";
            }
            return $option;
        }
    }


    public function create()
    {

        $confday = config('app.billing_cycle');


        // if (config('app.license_check') == true) {
        if (siteLicenseInfo() == "true" || config('app.license_check') == true) {
            if (license_check()['info']['client_type'] != "" && license_check()['info']['license_check'] != "") {
                if (license_check()['info']['client_limit'] != 0 && totalClientCount() >= license_check()['info']['client_limit']) {
                    abort(403, 'Your Limit crosed. Please contact software vendor. your limit was ' . license_check()['info']['client_limit'] . '. ');
                }
            }
        }
        $division = Division::all();

        // $areas = Clientsinfo::groupBy('area')->pluck('area');

        $areas = Clientsinfo::query()
            ->leftJoin('clients', 'clients.id', '=', 'clientsinfo.client_id')
            ->selectRaw('Distinct area')
            ->whereIn('clients.pop_id', userPops()->pluck('id')->toArray())
            ->pluck('area');

        $client_source = ClientSource::all();

        return view('clients.create', [
            'page_title' => 'Customer Add Form',
            'pop'        => Pop::conditionalList(),
            'confday'  => $confday,
            'marketer'   => ClientReferer::where('status', 'active')->get(),
            'areas'     => $areas,
            'client_source' => $client_source,
            'division' => $division,
            'upazila' => Upazila::all(),
            'district' => District::all()
        ]);
    }

    public function addMarketer(Request $request)
    {

        if (!empty($request->mfname) && !empty($request->mlname) && !empty($request->contact_no)) {

            if (ClientReferer::where('contact_no', $request->contact_no)->count() < 1) {



                ClientReferer::insert([
                    'firstname' => $request->mfname,
                    'lastname'  => $request->mlname,
                    'user_id'   => auth()->id(),
                    'contact_no' => $request->contact_no
                ]);
            } else {
                $error = 'Duplicate Contact No';
            }
        } else {
            $error = 'Input Data Empty';
        }

        $list = ClientReferer::all();
        return view('clients.marketerselect', ['marketer' => $list, 'error' => $error]);
    }

    public function addUpazila(Request $request)
    {
        if (!empty($request->upazila_district_id) && !empty($request->upazila_nama) && !empty($request->upazila_bn_name)) {
            if (Upazila::where('name', $request->upazila_nama)->count() < 1) {
                Upazila::insert([
                    'district_id' => $request->upazila_district_id,
                    'name'  => $request->upazila_nama,
                    'bn_name' => $request->upazila_bn_name
                ]);
                $error = 'Successfully Inserted';
            } else {
                $error = 'Duplicate Upazila';
            }
        } else {
            $error = 'Input Data Empty';
        }

        $list = Upazila::where('district_id', $request->upazila_district_id)->get();
        return view('clients.upazilaselect', ['upazila' => $list, 'error' => $error]);
    }

    public function addThana(Request $request)
    {
        if (!empty($request->thana_upazila_id) && !empty($request->thana_name) && !empty($request->thana_bn_name)) {
            if (Thana::where('name', $request->thana_name)->count() < 1) {
                Thana::insert([
                    'upazila_id' => $request->thana_upazila_id,
                    'name'  => $request->thana_name,
                    'bn_name' => $request->thana_bn_name
                ]);
                $error = 'Successfully Inserted';
            } else {
                $error = 'Duplicate Thana';
            }
        } else {
            $error = 'Input Data Empty';
        }

        $list = Thana::where('upazila_id', $request->thana_upazila_id)->get();
        return view('clients.thanaselect', ['thana' => $list, 'error' => $error]);
    }

    public function storeValidate($request, $custom = '')
    {

        if ($request->userid)

            return $this->validate($request, [
                'pop_id'            => 'required',
                'userid'            => 'required|unique:clients' . $custom,
                'package_id'        => 'required',
                // 'flat_no'        => 'required',
                'area'              => 'required',
                'billing_cycle'     => 'required',
                'password'          => 'required',
                'client_name'       => 'required',
                'contact_no'        => 'required',
                //'road_name'         => 'required',
                'national_id'       => 'required',
                //'owner_name'        => 'required',
                //'marketed_by'       => 'required',
                //'required_cable'    => 'required',
                //'olt_pon'           => 'required'
            ]);
    }

    public function store(Request $request)
    {
        // dd(date(1 . '-M-' . 2030));
        if (checkSettings('noBanglaCharacters') == 'enable') {
            $input = $request->all();
            $rules = [];

            // Apply the rule to all input fields
            foreach ($input as $field => $value) {
                $rules[$field] = new NoBangla();
            }
            $validator = Validator::make($input, $rules);

            if ($validator->fails()) {
                Toastr::error('Bangla Not Supported', 'Error');
                return redirect()->back()->withInput();
            }
        }


        if ($request->package_id == "Select a Package") {
            Toastr::error('Please Select a package', 'Error');
            return redirect()->back()->withInput();
        }

        if (!checkAPI()) {
            if ((preg_match('/[\'^£$%*()}{~?><>,|=+¬]/', $request->userid)) || (preg_match('/^\S.*\s.*\S$/', $request->userid))) {
                Toastr::error('Special Character Not Supported', 'Error');
                return redirect()->back()->withInput();
            }
        }

        if ($request->isStatic != 'on' && !Auth::user()->can("static_manage")) {
            $this->validate($request, [
                'userid' => 'required|unique:clients',
                "password" => 'required',
            ]);
        }

        $this->validate($request, [
            'pop_id' => 'required',
            'package_id' => 'required',
            'static_ip' => 'nullable|ipv4',

            'billing_cycle' => 'required',
            'client_name' => 'required',
            'contact_no' => 'required',

        ]);

        // i want validate mac address is it valid mac or not
        if ($request->mac) {
            if (!preg_match('/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/', $request->mac)) {
                Toastr::error('Invalid MAC Address', 'Error');
                return redirect()->back()->withInput();
            }
        }

        if ($request->ipv6) {
            $ipv6 = trim($request->ipv6);

            // Check if format contains '/'
            if (empty($ipv6) || !str_contains($ipv6, '/')) {
                Toastr::error('Invalid IPv6 prefix format. Expected format: 2001:db8::/32', 'Error');
                return redirect()->back()->withInput();
            }

            [$ip, $prefix] = explode('/', $ipv6, 2);

            // Trim whitespace from both parts
            $ip = trim($ip);
            $prefix = trim($prefix);

            // Validate IP address
            if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
                Toastr::error('Invalid IPv6 address', 'Error');
                return redirect()->back()->withInput();
            }

            // Validate prefix is numeric and within range
            if (empty($prefix) || !is_numeric($prefix)) {
                Toastr::error('IPv6 prefix must be a number', 'Error');
                return redirect()->back()->withInput();
            }

            $prefix = (int)$prefix;
            if ($prefix < 0 || $prefix > 128) {
                Toastr::error('IPv6 prefix must be between 0 and 128', 'Error');
                return redirect()->back()->withInput();
            }

            // Optionally store the validated values
            // $request->merge(['ipv6_address' => $ip, 'ipv6_prefix' => $prefix]);
        }




        if (checkSettings('number_validate') == 'enable') {
            $numberValidation = new NumberValidation();
            if (!$numberValidation->isBangladeshiNumber($request->contact_no)) {
                Toastr::error('Invalid Bangladeshi Number', 'Error');
                return redirect()->back()->withInput();
            }
        }

        $pop = Pop::with("nas")->find($request->pop_id);

        $expire = ExpireCheck::expireNew($pop, $request->package_id, $request->billing_cycle);



        if (config('app.full_month_bill_for_new_customer') == true) {

            if (checkSettings('only_full_bill_for_local_client') == 'enable') {
                if ($pop->bill_generate == 'yes') {
                    if ($pop->subreseller == 'yes') {
                        $sub_package_find = SubPackage::find($request->package_id);
                        $package_find = Packages::find($sub_package_find->package_id);
                        $expire['cost'] = $package_find->package_rate ?? 0;
                        $expire['reseller_cost'] = $package_find->package_rate ?? 0;
                        $expire['subResellerCost'] = $sub_package_find->rate;
                    } else {
                        $package_find = Packages::find($request->package_id);
                        $expire['cost'] = $package_find->package_rate ?? 0;
                        $expire['reseller_cost'] = $package_find->package_rate ?? 0;
                    }
                }
            } else {
                if ($pop->subreseller == 'yes') {
                    $sub_package_find = SubPackage::find($request->package_id);
                    $package_find = Packages::find($sub_package_find->package_id);
                    $expire['cost'] = $package_find->package_rate ?? 0;
                    $expire['reseller_cost'] = $package_find->package_rate ?? 0;
                    $expire['subResellerCost'] = $sub_package_find->rate;
                } else {
                    $package_find = Packages::find($request->package_id);
                    $expire['cost'] = $package_find->package_rate ?? 0;
                    $expire['reseller_cost'] = $package_find->package_rate ?? 0;
                }
            }
        }
        // dd($expire);


        if (getBillingType() == 'day_to_day') {
            if (!auth()->user()->can('day-to-day-reseller-full-date')) {
                $expire['cost'] = 0;
                $expire['exp_date'] = today()->subDay()->format('d-M-Y');
                $expire['total_date'] = 0;
                $expire['reseller_cost'] = 0;
                // $expire['curBalance'] = 1;
                $expire['subResellerCost'] = 0;
            }
        }

        if ($request->is_free == '1') {

            $expire['cost'] = 0;
            $expire['exp_date'] = Carbon::parse(date($request->billing_cycle . '-M-' . 2100))->format('d-M-Y');
            $expire['total_date'] = 0;
            $expire['reseller_cost'] = 0;
            $expire['curBalance'] = 1;
        }

        $totalResellerCost = 0;
        $totalSubResellerCost = 0;
        $reseller = Reseller::find($pop->reseller_id);

        if (globalPermission('check_client_balance_before_package_billing_date_change') && $reseller->reseller_type == 'own') {
            $totalResellerCost = $expire['reseller_cost'];
            if ($pop->subreseller == 'yes') {
                $totalSubResellerCost = $expire['subResellerCost'];
            }
        } else {
            $totalResellerCost = $expire['reseller_cost'] + $request->otc;
            if ($pop->subreseller == 'yes') {
                $totalSubResellerCost = $expire['subResellerCost'] + $request->otc;
            }
        }

        if ($pop->billable == 'yes') {
            if ($totalResellerCost > $expire['curBalance'] && getBillingType() != 'day_to_day') {

                Toastr::error('Not Enough Balance Reseller Account', 'Error');
                return redirect()->back()->withInput();
            }

            // dd($expire['subReseller'], $expire['subResellerCost'] + $request->otc);

            if ($expire['subReseller'] == 'yes' && $totalSubResellerCost > $expire['subResellerBalance']) {
                Toastr::error('Not Enough Balance Sub Reseller Account', 'Error');
                return redirect()->back()->withInput();
            }
        }

        $reseller_id = $pop->reseller_id;

        $action = "New MAC added. Package Name: " . $expire['reseller_package_name'] . " Expire: " . $expire['exp_date'] .
            ". For " . $expire['total_date'] . " days cost BDT " . $expire['reseller_cost'];

        if ($expire['subReseller'] == 'yes') {
            $SubResellerAction = "New MAC added. Package Name: " . $expire['sub_reseller_package_name'] . " Expire: " .
                $expire['exp_date'] . ". For " . $expire['total_date'] . " days cost BDT " . $expire['subResellerCost'];
        }

        // dd($action);

        DB::beginTransaction();

        try {

            if ($reseller->reseller_type == 'own') {
                $otc = $request->otc ?? 0;
                $extra_remark = $otc > 0 ? ' OTC : ' . $otc : '';
            } else {
                $otc = 0;
                $extra_remark = '';
            }





            if (globalPermission('check_client_balance_before_package_billing_date_change') && $reseller->reseller_type == 'own') {
                $extra_remark = '';
            }


            if (!Auth::user()->can("static_manage") && $request->isStatic == 'on') {
                Toastr::error('You are not allowed to create static IP', 'Error');
                return redirect()->back();
            }

            $client_id = ClientServices::clientCreate($request, $expire);

            // if (getBillingType() == 'day_to_day') {
            $resellerBalanceLogD2D = ReselleBalanceLogReport::create(
                [
                    'reseller_id' => $reseller_id,
                    'client_id' => $client_id,
                    'action' => $action . $extra_remark ?? '',
                    'amount' => $totalResellerCost,
                    'remarks' => 'Created BY ' . Auth::user()->email,
                    'uniqueId' => $request->uuid,
                    'pop_id' => $pop->id,
                    'commission_amount' => getCommissionForResellerRecharge($client_id, $totalResellerCost),
                    'reseller_commission_percentage' => $reseller->commission_percentage,
                    'pop_commission_percentage' => $pop->commission_percentage,
                ]
            );
            Balance::balanceDeductForUserRecharge('reseller', $reseller_id, $totalResellerCost);
            $package = Packages::find($expire['reseller_package_id']);
            if ($pop->bill_generate == 'yes') {
                $bill_id =  $this->localCustomerPaymentProcess($reseller, $request, $client_id, $expire, $otc, $package);
            }

            if ($expire['subReseller'] == 'yes') {

                Balance::balanceDeductForUserRecharge('pop', $pop->id, $totalSubResellerCost);

                SubResellerBalanceLogReport::create(
                    [
                        'reseller_id' => $reseller_id,
                        'sub_reseller_id' => $pop->id,
                        'client_id' => $client_id,
                        'action' => $SubResellerAction . $extra_remark ?? '',
                        'amount' => $totalSubResellerCost,
                        'remarks' => 'Created BY ' . Auth::user()->email,
                        'reseller_cost' => $totalResellerCost,
                        'commission_amount' => getCommissionForSubResellerRecharge($client_id, $totalSubResellerCost),
                        'reseller_balance_log_id' => $resellerBalanceLogD2D->id,

                    ]
                );

                $sub_packages = SubPackage::find($expire['sub_reseller_package_id']);
                if ($sub_packages->commission > 0 || globalPermission('commission_from_manager_pop')) {
                    (new CommissionService())->subreseller_commission(
                        $totalSubResellerCost,
                        $action,
                        $pop->id,
                        $sub_packages->commission,
                        $sub_packages->rate,
                        $client_id
                    );
                }
            }
            // }

            $logClient = Client::where('id', $client_id)->first();
            $old_client_data = Client::with('clientsinfo')->find($logClient->id);

            if ($reseller->reseller_type == 'other') {
                $logClient->first_approval = 'Approved';
                $logClient->update();
            }

            $new_client_data = Client::with('clientsinfo')->find($logClient->id);
            $this->clientEditLog($logClient, $old_client_data, $new_client_data);



            // if (getBillingType() != 'day_to_day' || auth()->user()->can('day-to-day-reseller-full-date')) {

            //     $resellerBalanceLogReport = ReselleBalanceLogReport::create(
            //         [
            //             'reseller_id' => $reseller_id,
            //             'client_id' => $client_id,
            //             'action' => $action . $extra_remark ?? '',
            //             'amount' => $expire['reseller_cost'] + ($reseller->reseller_type == 'own' ? $otc : 0),
            //             'remarks' => 'Created BY ' . Auth::user()->email,
            //             'uniqueId' => $request->uuid,
            //             'pop_id' => $pop->id,
            //             'commission_amount' => getCommissionForResellerRecharge($client_id, ($expire['reseller_cost'] + ($reseller->reseller_type == 'own' ? $otc : 0))),
            //             'reseller_commission_percentage' => $reseller->commission_percentage,
            //             'pop_commission_percentage' => $pop->commission_percentage,
            //         ]
            //     );


            //     $package = Packages::find($expire['reseller_package_id']);



            //     if ($pop->bill_generate == 'yes') {
            //         $bill_id =  $this->localCustomerPaymentProcess($reseller, $request, $client_id, $expire, $otc, $package);
            //     }

            //     if ($package->commission > 0 || globalPermission('commission_from_manager_pop')) {
            //         (new CommissionService())->reseller_commission(
            //             $expire['reseller_cost'],
            //             $action,
            //             $reseller_id,
            //             $package->commission,
            //             $package->package_rate,
            //             $client_id,
            //             'bill',
            //             $bill_id ?? null,
            //         );
            //     }

            //     if ($pop->billable == 'yes') {

            //         Balance::balanceDeductForUserRecharge('reseller', $reseller_id, $expire['reseller_cost'] + $otc);

            //         if ($expire['subReseller'] == 'yes') {

            //             Balance::balanceDeductForUserRecharge('pop', $pop->id, $expire['subResellerCost'] + $otc);

            //             SubResellerBalanceLogReport::create(
            //                 [
            //                     'reseller_id' => $reseller_id,
            //                     'sub_reseller_id' => $pop->id,
            //                     'client_id' => $client_id,
            //                     'action' => $SubResellerAction . $extra_remark ?? '',
            //                     'amount' => $expire['subResellerCost'] + ($reseller->reseller_type == 'own' ? $otc : 0),
            //                     'remarks' => 'Created BY ' . Auth::user()->email,
            //                     'reseller_cost' => $expire['reseller_cost'] + $otc,
            //                     'commission_amount' => getCommissionForSubResellerRecharge($client_id, ($expire['subResellerCost'] + ($reseller->reseller_type == 'own' ? $otc : 0))),
            //                     'reseller_balance_log_id' => $resellerBalanceLogReport->id,

            //                 ]
            //             );

            //             $sub_packages = SubPackage::find($expire['sub_reseller_package_id']);
            //             if ($sub_packages->commission > 0 || globalPermission('commission_from_manager_pop')) {
            //                 (new CommissionService())->subreseller_commission(
            //                     $expire['subResellerCost'],
            //                     $action,
            //                     $pop->id,
            //                     $sub_packages->commission,
            //                     $sub_packages->rate,
            //                     $client_id
            //                 );
            //             }
            //         }
            //     }
            // }

            if (Auth::user()->can("client_auto_approve")) {

                ClientApproveService::approveClients([$client_id], true);
            }

            // add this to commit

            if ($pop->bill_generate == 'yes' && getBillingType() != 'day_to_day') {


                if ((Carbon::parse($expire['exp_date']) < today()->endOfMonth()) && (config('app.full_month_bill_for_new_customer') == false)) {

                    CustomerAccount::updateCustomrAccount($client_id, $package->package_rate, 0, 0, $package->package_rate);
                    BillGenerateController::entryBillGenerate(
                        $client_id,
                        $package->package_rate,
                        'Monthly Bill Generate',
                        'monthly',
                        $expire['exp_date']
                    );
                } else {
                    BillGenerateController::entryBillGenerate(
                        $client_id,
                        0,
                        'Monthly Bill Generate',
                        'monthly',
                        $expire['exp_date']
                    );
                }
            }


            DB::commit();



            (new Notification)->notify("..::[Customer Add]::..\n New Customer Added by " . auth()->user()->name . " \nCustomer Username : " . $request->userid . " \nPassword : " . $request->password);

            return redirect()->back()->with('success_message', 'User ID Added..');
        } catch (Throwable $e) {

            DB::rollback();
            Toastr::error($e->getMessage(), 'Failed');
            return back();
        }
    }

    public function localCustomerPaymentProcess($reseller, $request, $client_id, $expire, $otc, $package)
    {

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

            if ($request->bill_amount_paid == 1) {

                $actions = 'New User create. cost ' . $expire['reseller_cost'] . 'TK for the customer ' . $request->userid;

                UserAccounting::userAcStore($expire['reseller_cost'], $actions, $client_id, '', 'new_customer');
            }

            if ($request->otc != null && $request->otc > 0 && checkSettings('otc-auto-due') == 'disable') {

                $actions = 'New User create. OTC Collect. ' . $otc . 'TK for customer ' . $request->userid;
                UserAccounting::userAcStore($otc, $actions, $client_id, '', 'otc');
            }
        }


        CustomerAccount::updateCustomrAccount($client_id, $expire['cost'] + $request->otc, 0, 0, $expire['cost'] + $request->otc);

        if (config('app.full_month_bill_for_new_customer') == true) {
            $cost = $package->package_rate;
        } else {
            $cost = $expire['cost'];
        }

        if (Client::find($client_id)->is_free == 1) {
            $cost = 0;
        }
        if (getBillingType() != 'day_to_day') {
            $bill_new_customer_entry = BillGenerateController::entryBillGenerate(
                $client_id,
                $cost,
                'New Customer Entry',
                'new',
                $expire['exp_date']
            );
        }

        $this->otcProcess($request, $client_id, $otc);

        if (getBillingType() != 'day_to_day') {
            if ($request->bill_amount_paid == 1) {
                (new PaymentController)->newUserPaymentProcess($client_id);
            }
            return $bill_new_customer_entry->id;
        }
    }

    public function otcProcess($request, $client_id, $otc)
    {
        if ($request->otc != null and $request->otc > 0) {

            BillGenerateController::entryBillGenerate(
                $client_id,
                $request->otc,
                'New Customer OTC',
                'otc',
                ''
            );

            if (checkSettings('otc-auto-due') == 'disable') {

                $income_type = IncomeHead::find(2);
                $income = new Income();
                $income->name = $income_type->name;
                $income->date = now();
                $income->amount = $otc;
                $income->description = 'Bill Payment for customer : ' . $request->userid;
                $income->incomeHead = $income_type->id;
                $income->save();

                (new PaymentController)->newUserOTCPaymentProcess($client_id, $otc, $income->id);
            }
        }
    }


    public function getSpeed(Request $request)
    {

        $user = Client::with('pop.nas')->find($request->id);

        $pppoe_user = str_replace(' ', '_', $user->userid);
        $accounting = new Accounting();
        $userinfo = $accounting->lastOnlineOfSingleUser($pppoe_user);


        if (!$userinfo && !checkAPI()) {
            return response('User not Online', 404);
        }
        $mikrotick_info =  checkAPI() ? $user->pop->nas : Nas::where('nasname', $userinfo->nasipaddress)->first();

        if (!$mikrotick_info) {
            return response("MikroTik Not Found ", 404);
        }


        $mk = new Mikrotik($mikrotick_info->nasname, $mikrotick_info->mikrotick_user, $mikrotick_info->mikrotick_user_password, $mikrotick_info->mikrotick_port ? (int)$mikrotick_info->mikrotick_port : 8728);
        for ($i = 0; $i < 45; $i++) {
            try {
                $response = $mk->getSpeed($user->userid);
                $result = json_encode($response);
                event(new SecondEvent($request->uuid, $result));
            } catch (Exception $err) {
                return response($err->getMessage(), 404);
            }
        }

        return true;
    }

    function formatBandwidth($octets)
    {
        $bandwidth = ($octets) / (8 * 1024 * 1024);
        return round($bandwidth, 2);
    }

    public function show($id)
    {
        $list = ClientServices::customerList('singleUser', $id);

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

        $pppoe_user = str_replace(' ', '_', $user->userid);

        $accounting = new Accounting();

        $userinfo = $accounting->lastOnlineOfSingleUser($pppoe_user);

        $liveSpeedInfo = clientLiveSpeed::liveSpeed($user, $userinfo);

        $customer_payment = CustomerAccount::where('client_id', $id)->count();

        $uploadSpeed = 0;
        $downloadSpeed = 0;
        if (checkSettings('radius-upload-download') == 'enable') {
            if ($userinfo) {
                $username = $userinfo->username;
                $startDate = $userinfo->acctstarttime;
                $endDate = $userinfo->acctstoptime == null ? now() : $userinfo->acctstoptime;

                $accountingRecords = DB::table('radacct')->where('username', $username)
                    // ->whereBetween('acctstarttime', [$startDate, $endDate])
                    ->where('acctstarttime', '>=', Carbon::now()->subDay()->toDateTimeString())
                    ->get();

                foreach ($accountingRecords as $record) {
                    $uploadSpeed += $record->acctoutputoctets;
                    $downloadSpeed += $record->acctinputoctets;
                }
                $uploadSpeed = $this->formatBandwidth($uploadSpeed);
                $downloadSpeed = $this->formatBandwidth($downloadSpeed);
            }
        }

        $onuInfo = null;
        if (globalPermission("onu_information_laser")) {
            $onuInfo = OltOnuInformation::where('username', $pppoe_user)->first();
        }

        return view('clients.details', [
            'onuInfo' => $onuInfo,
            'error' => $liveSpeedInfo['error'],
            'bandwidthUsage' => $liveSpeedInfo['bandwidthUsage'],
            "lastLogoutTime" => $liveSpeedInfo['lastLogoutTime'],
            'list' => $list->get(),
            'page_title' => 'Customer Details Information',
            'pop' => Pop::all(),
            'user_id' => auth()->user()->id,
            'customer_account' => $customer_payment,
            'uploadSpeed' => $uploadSpeed,
            'downloadSpeed' => $downloadSpeed,
        ]);
    }

    public function edit($id)
    {
        $popid = Client::pop_ids();

        $client = Client::with('clientsinfo', 'packages', 'pops')
            ->where('id', $id)->withTrashed();
        if (auth()->user()->hasRole(['Sub Reseller', 'Reseller', 'Reseller Admin'])) {
            $client->whereIn('pop_id', $popid);
        }
        $client = $client->first();


        if (!$client->first()) {
            return redirect()->route('clients.index');
        }


        $reseller = Pop::where('id', $client->pop_id)->first();
        $popArea = ResellerArea::where('reseller_id', $reseller->reseller_id)->get();
        // $popArea = ResellerArea::where('pop_id', $client->pop_id)->get();

        $areas = Clientsinfo::groupBy('area')->pluck('area');
        $company_information = CompanyInformation::latest()->first();
        // dd($list);

        // Static Ip
        $ip = null;
        $ports = [];
        $interfaces = [];
        $datas = null;
        if (checkAPI() && checkSettings('static-ip-check') == 'enable') {
            $popId = $reseller->id;
            $package = $client->packages->profile_name;
            $nas = Nas::where('id', $reseller->nas_id)->first();
            // dd($nas->mikrotick_user_password);
            $ip = $this->ipRange($package, $nas, $popId);
        } elseif (checkAPI() && checkSettings('static_ip_manage') == 'enable') {
            $nas = Nas::where('id', $reseller->nas_id)->first();

            //for static ip port
            $datas = json_decode($nas->ip_block);


            $ports = [];
            if ($datas != null) {
                foreach ($datas as $data) {
                    $ports[] = $data->port;
                }
            }


            //for static ip
            try{
                $mk = new MikrotikStaticIP($nas->nasname, $nas->mikrotick_user, $nas->mikrotick_user_password, $nas->mikrotick_port ? (int)$nas->mikrotick_port : 8728);

                $blocks = [];
                if ($nas->ip_block != null) {
                    $blocks = json_decode($nas->ip_block);
                }

                $ipblock = null;
                foreach ($blocks as $block) {
                    if ($block->id == request()->id) {
                        $ipblock = $block->ip_block;
                    }
                }

                if ($nas->ip_block != null) {
                    $staticIp = getStaticIpFromBlock($ipblock);
                } else {
                    $staticIp = [$client->ip_address];
                }

                $clientsip = Client::pluck('ip_address')->all();

                $results = array_diff($staticIp, $clientsip);

                $ip = '';

                foreach ($results as $result) {
                    // if (Client::where('ip_address', $ip)) {
                    $ip .= "<option value=\"$result\">$result</option>";
                    // }
                }
            } catch (Exception $err) {
                Toastr::error($err->getMessage(), 'Error');
            }
        }

        $boxs = Box::where('pop_id', $client->pop_id)->get();



        // dd($box);

        $division = Division::all();
        $district = District::all();
        $upazila = Upazila::all();
        $thana = Thana::where('upazila_id', $client->clientsinfo->upazila)->orderBy('name', 'ASC')->get();
        $client_source = ClientSource::all();

        return view('clients.edit', [
            'r' => $client,
            'page_title' => 'Customer Edit',
            'pop' => Pop::conditionalList(),
            'popArea' => $popArea,
            'areas' => $areas,
            'company_information' => $company_information,
            'ip' => $ip,
            'marketer'   => ClientReferer::where('status', 'active')->get(),
            'client_source' => $client_source,
            'division' => $division,
            'district' => $district,
            'upazila' => $upazila,
            'thana' => $thana,
            'ports' => $ports,
            'boxs' => $boxs,
            'datas' => $datas,
        ]);
    }

    public function clientEditLog($client, $old_client, $new_data_client)
    {
        $client_update_log = new ClientEditLog();
        $client_update_log->client_id = $client->id;
        $client_update_log->user_id = Auth::user()->id;
        $client_update_log->old_data = json_encode($old_client);
        $client_update_log->new_data = json_encode($new_data_client);
        $client_update_log->save();
    }


    public function update(Request $request, $id)
    {
        if (checkSettings('noBanglaCharacters') == 'enable') {
            $input = $request->all();
            $rules = [];

            // Apply the rule to all input fields
            foreach ($input as $field => $value) {
                $rules[$field] = new NoBangla();
            }

            $validator = Validator::make($input, $rules);

            if ($validator->fails()) {
                // Get names of all fields that failed
                $failedFields = array_keys($validator->failed());

                // Format field names into a string
                $fieldList = implode(', ', $failedFields);

                // Show which fields failed
                Toastr::error("Bangla Not Supported in: $fieldList", 'Error');

                return redirect()->back()->withInput();
            }
        }

        $client = Client::withTrashed()->find($id);
        $package = Packages::find($client->package_id);
        $packagePrice = $package->package_rate;
        if ($packagePrice < $request->parmanent_discount) {
            Toastr::error('Discount can not be greater than package price', 'Error');
            return redirect()->back();
        }
        if (!checkAPI()) {
            if ((preg_match('/[\'^£$%&*()}{~?><>,|=+¬]/', $request->userid)) || (preg_match('/^\S.*\s.*\S$/', $request->userid))) {
                return redirect()->back()->with('error_message', 'Special Character Not Supported');
            }
        }

        $company_information = CompanyInformation::latest()->first();

        if ($request->payment_dadeline > $company_information->max_extended_day) {
            Toastr::error("Please Select Temporary Extend (days) between 0 to" . $company_information->max_extended_day);
            return back();
        }



        $this->validate($request, [
            'pop_id' => 'required',
            'userid' => 'required|unique:clients,userid,' . $client->id,
            'ip_address' => 'nullable|ipv4',
            'password' => 'required',
            'client_name' => 'required',
            'contact_no' => 'required',

        ]);

        if (checkSettings('number_validate') == 'enable') {
            $numberValidation = new NumberValidation();
            if (!$numberValidation->isBangladeshiNumber($request->contact_no)) {
                Toastr::error('Invalid Bangladeshi Number', 'Error');
                return redirect()->back()->withInput();
            }
        }

        if ($request->mac) {
            if (!preg_match('/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/', $request->mac)) {
                Toastr::error('Invalid MAC Address', 'Error');
                return redirect()->back()->withInput();
            }
        }

        if ($request->ipv6) {
            $ipv6 = trim($request->ipv6);

            // Check if format contains '/'
            if (empty($ipv6) || !str_contains($ipv6, '/')) {
                Toastr::error('Invalid IPv6 prefix format. Expected format: 2001:db8::/32', 'Error');
                return redirect()->back()->withInput();
            }

            [$ip, $prefix] = explode('/', $ipv6, 2);

            // Trim whitespace from both parts
            $ip = trim($ip);
            $prefix = trim($prefix);

            // Validate IP address
            if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
                Toastr::error('Invalid IPv6 address', 'Error');
                return redirect()->back()->withInput();
            }

            // Validate prefix is numeric and within range
            if (empty($prefix) || !is_numeric($prefix)) {
                Toastr::error('IPv6 prefix must be a number', 'Error');
                return redirect()->back()->withInput();
            }

            $prefix = (int)$prefix;
            if ($prefix < 0 || $prefix > 128) {
                Toastr::error('IPv6 prefix must be between 0 and 128', 'Error');
                return redirect()->back()->withInput();
            }

            // Optionally store the validated values
            // $request->merge(['ipv6_address' => $ip, 'ipv6_prefix' => $prefix]);
        }


        DB::beginTransaction();


        try {
            $old_client = Client::with('clientsinfo')->withTrashed()->find($client->id);
            $oldPop = Pop::with("nas", 'reseller')->find($client->pop_id);
            $newPop = Pop::with("nas", 'reseller')->find($request->pop_id);

            $previous_bandwidth_limit = $client->bandwidth_limit;
            $previous_apply_bandwidth_limit = $client->apply_bandwidth_limit;

            $previous_client_approval = $client->client_approval;

            if ($client->payment_dadeline < $request->payment_dadeline) {
                try {
                    sendSmsAfterExtended($client->id, $request->payment_dadeline);
                } catch (\Exception $e) {
                }
            }



            ClientServices::clientUpdate($request, $client);

            $new_data_client = Client::with('clientsinfo', 'packages')->withTrashed()->find($client->id);

            $this->clientEditLog($client, $old_client, $new_data_client);

            $new_bandwidth_limit = $new_data_client->bandwidth_limit;
            $new_apply_bandwidth_limit = $new_data_client->apply_bandwidth_limit;
            $checkDisableAndTakeActionForLmitChange = ($previous_bandwidth_limit != $new_bandwidth_limit || $previous_apply_bandwidth_limit != $new_apply_bandwidth_limit)
                && $new_data_client->clients_status == "disable";
            if ($checkDisableAndTakeActionForLmitChange) {
                $user_log = User_log::where('client_id', $client->id)->orderBy('created_at', 'desc')->limit(1)->get();
                if ($user_log[0]["log_type"] == "id_disable" && $user_log[0]["user_id"] == 1 && $user_log[0]["details"] == "limit over") {
                    (new DisableLimitOverUserController())->checkLimitCustomerAndProceed(
                        $new_data_client->id,
                        $new_data_client->up_bandwidth,
                        $new_data_client->down_bandwidth,
                        $new_data_client->bandwidth_limit,
                        $new_data_client->packages->limite_quantity,
                        $new_data_client->apply_bandwidth_limit
                    );
                }
            }
            if (globalPermission('RadiusExpiration')) {

                (new ExpirationService())->handleExpiration($client->userid, $old_client->expire_date, $new_data_client->payment_dadeline, $oldPop->experity_check);
            }

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


            if (globalPermission('save_billing_start_date_on_reseller_change')) {

                if ($oldPop->reseller_id != $newPop->reseller_id) {

                    if ($newPop->reseller->reseller_type == 'own' && $oldPop->reseller->reseller_type == 'other') {
                        $client->billing_start_date = now();
                        $client->save();
                    }
                } else {
                    if ($newPop->reseller->reseller_type == 'own' && $newPop->subreseller == 'yes' && $oldPop->subreseller == 'no') {
                        $client->billing_start_date = now();
                        $client->save();
                    }
                }
            }



            DB::commit();


            if (
                $previous_client_approval != "pending"
                && checkAPI() && $client->client_approval != "pending"
                && !$request->ignoreMkCheck
            ) {

                if (checkAPI()) {
                    $sync = new SyncWithMk();
                    if ($client->deleted_at == null) {
                        if ($client->isStatic && ($client->ip_address != $old_client->ip_address)) {
                            $mk = new MikrotikStaticIP($oldPop->nas->nasname, $oldPop->nas->mikrotick_user, $oldPop->nas->mikrotick_user_password, $oldPop->nas->mikrotick_port ? (int)$oldPop->nas->mikrotick_port : 8728);
                            $mk->updateStaticIP($old_client->ip_address, [
                                "ip_address" => $client->ip_address,
                            ]);
                            $sync->syncSingleClient($client->id);
                        } else {
                            $sync->syncSingleClient($client->id);
                        }
                    }
                }



                if ($old_client->userid != $request->userid || $newPop->nas->nasname != $oldPop->nas->nasname) {
                    $previous_mikrotik = $oldPop->nas;
                    $mkIp = $previous_mikrotik->nasname;
                    $mkUser = $previous_mikrotik->mikrotick_user;
                    $mkPass = $previous_mikrotik->mikrotick_user_password;
                    $mkPort = $previous_mikrotik->mikrotick_port;
                    $mk = new Mikrotik($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
                    try {
                        $mk->disconnectSecret($old_client->userid);
                    } catch (Exception $err) {
                    }

                    try {
                        $mk->deleteSecret($old_client->userid);
                    } catch (Exception $err) {
                        Toastr::error('Failed to delete');
                        return redirect()->back();
                    }
                }
            }


            (new Notification)->notify("..::[Customer Edit]::.. \n Customer Information Update.\nUpdate By " . auth()->user()->name . " \nCustomer Username : " . $client->userid . " \nPassword : " . $client->password . "\nUpdate Time : " . now());

            Toastr::success('User Update Successfully', 'success');
            return redirect()->back();
        } catch (Exception $e) {

            DB::rollback();
            Toastr::error($e->getMessage(), 'Failed');
            return back();
        }
    }

    public function close($id, $roleIgnore = false, $userId = null)
    {


        if (!$roleIgnore && auth()->user()->hasRole(['Sub Reseller', 'Reseller', 'Reseller Admin'])) {
            $client = Client::where('id', $id)->whereIn('pop_id', Client::pop_ids())->first();
        } else {
            $client = Client::find($id);
        }

        if (!$client) {
            return redirect()->back()->with('error_message', 'Client Not Found');
        }

        DB::beginTransaction();
        try {
            if (checkAPI()) {
                if (!globalPermission("close-or-deactive-without-mikrotik")) {
                    $mkIp = $client->pop->nas->nasname;
                    $mkUser = $client->pop->nas->mikrotick_user;
                    $mkPass = $client->pop->nas->mikrotick_user_password;
                    $mkPort = $client->pop->nas->mikrotick_port;
                    if ($client->isStatic) {
                        $mk = new MikrotikStaticIP($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
                        $mk->disableStaticIP($client->ip_address);
                    } else {

                        $mk = new Mikrotik($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
                        try {
                            $mk->disconnectSecret($client->userid);
                        } catch (Exception $err) {
                        }
                        $info = $mk->getSecret();
                        foreach ($info as $value) {
                            if ($value['name'] == $client->userid) {
                                $client_info = Clientsinfo::where('client_id', $client->id)->first();
                                $client_info->remarks = $client_info->remarks . ". [Last Log Out Time = " . $value['last-logged-out'] . "]" ?? '';
                                $client_info->save();
                            }
                        }
                        $mk->deleteSecret($client->userid);
                    }
                }
                $client->closed_at = Carbon::now();
                $client->save();
            } else {
                DB::table('radcheck')
                    ->whereUsername($client->userid)
                    ->delete();

                ClientSyncJobForSingle::dispatch($client->id);
            }
            // User Log
            $user_log = new User_log();
            $user_log->log_type = "id_close";
            $user_log->user_id =  $userId ? $userId : auth()->user()->id;
            $user_log->details = "Client Close";
            $user_log->client_id = $client->id;
            $user_log->save();
        } catch (Exception $err) {
            DB::rollBack();
            // throw new Exception($err, 1);
            return response()->json([
                'status' => 'error',
                'message' => "Something went wrong",

            ]);
        }

        $client->delete();


        DB::commit();
        (new Notification)->notify("..::[Customer Close]::.. \n Customer Information Closed.\nClose By " . auth()->user()->name . " \nCustomer Username : " . $client->userid . " \nPassword : " . $client->password . "\nClose Time : " . now());
        return response()->json([
            'status' => 'success',
            'message' => 'User Close Successfully',
        ]);
    }

    public function open($id, request $request)
    {
        // if (config('app.license_check') == true) {
        if (siteLicenseInfo() == "true" || config('app.license_check') == true) {
            if (license_check()['info']['client_type'] != "" && license_check()['info']['license_check'] != "") {
                if (license_check()['info']['client_limit'] != 0 && totalClientCount() > license_check()['info']['client_limit']) {
                    abort(403, 'Your Limit crosed. Please contact software vendor. your limit was ' . license_check()['info']['client_limit'] . '. ');
                }
            }
        }
        $client = Client::withTrashed()->where('id', $id);

        if (auth()->user()->hasRole(['Sub Reseller', 'Reseller', 'Reseller Admin'])) {
            $client = $client->whereIn('pop_id', Client::pop_ids())->first();
        } else {
            $client = $client->first();
        }

        if (!$client) {
            return redirect()->route('clients.index');
        }



        if (checkAPI()) {
            DB::beginTransaction();
            try {
                $client->restore();
                $clientdetails = Clientsinfo::where('client_id', $client->id)->first();
                $clientdetails->joinDate = Carbon::now();
                $clientdetails->save();
                $syncWithMk = new SyncWithMk();
                $syncWithMk->syncSingleClient($client->id);

                $user_log = new User_log();
                $user_log->log_type = "id_enable";
                $user_log->user_id =  auth()->user()->id;
                $user_log->details = "Client restore";
                $user_log->client_id = $client->id;
                $user_log->save();

                DB::commit();
                (new Notification)->notify("..::[Customer Restore]::.. \n Customer Opened.\nOpen By " . auth()->user()->name . " \nCustomer Username : " . $client->userid . " \nPassword : " . $client->password . "\nOpen Time : " . now());
                Toastr::success('Your Action The ' . $client->userid . ' is successfully Opened', 'success');
                return redirect()->back();
            } catch (Exception $err) {
                DB::rollBack();
                dd($err);
                Toastr::error('Something is wrong.', 'error');
                return redirect()->back();
            }
        } else {
            $client->restore();
            $clientdetails = Clientsinfo::where('client_id', $client->id)->first();
            $clientdetails->joinDate = Carbon::now();
            $clientdetails->save();
            $idEnable = new IdEnableDisableController;
            $idEnable->idEnable($client->id, 'Client restore');
            $status = 'success';

            (new Notification)->notify("..::[Customer Restore]::.. \n Customer Opened.\nOpen By " . auth()->user()->name . " \nCustomer Username : " . $client->userid . " \nPassword : " . $client->password . "\nOpen Time : " . now());
            if ($status == 'success') {
                Toastr::success('Your Action The ' . $client->userid . ' is successfully Opened', 'success');
                return redirect()->back();
            } else {
                Toastr::error('Something is wrong.', 'error');
                return redirect()->back();
            }
        }
    }

    public function destroy($id)
    {

        $client = Client::withTrashed()->where('id', $id);
        if (auth()->user()->hasRole(['Sub Reseller', 'Reseller', 'Reseller Admin'])) {
            $client = $client->whereIn('pop_id', Client::pop_ids())->first();
        } else {
            $client = $client->first();
        }

        if (!$client) {
            // return redirect()->route('clients.index');
            return response()->json([
                'status' => 'error',
                'message' => 'Client Not Found',
            ]);
        }


        $payment = Billpayment::where('client_id', $client->id)->first();

        // dd($payment);
        if (empty($payment) || $client->client_approval == 'pending') {

            DB::beginTransaction();

            try {
                $pop = Pop::with("reseller")->find($client->pop_id);

                try {
                    DB::statement("delete from radcheck where username='$client->userid'");
                } catch (\Exception $e) {
                    // Ignore errors
                }

                try {
                    DB::statement("delete from radusergroup where username='$client->userid'");
                } catch (\Exception $e) {
                    // Ignore errors
                }

                try {
                    DB::statement("delete from radacct where username='$client->userid'");
                } catch (\Exception $e) {
                    // Ignore errors
                }

                try {
                    DB::statement("delete from customer_accounts where client_id=$client->id");
                } catch (\Exception $e) {
                    // Ignore errors
                }

                try {
                    DB::statement("delete from bill_generates where client_id=$client->id");
                } catch (\Exception $e) {
                    // Ignore errors
                }

                try {
                    DB::statement("delete from clientsinfo where client_id=$client->id");
                } catch (\Exception $e) {
                    // Ignore errors
                }

                try {
                    DB::statement("delete from clients where id=$client->id");
                } catch (\Exception $e) {
                    // Ignore errors
                }


                if ($client->client_approval == 'pending') {

                    $reseller_balance_log = DB::table('reselle_balance_log_reports')->where('client_id', $client->id)->first();
                    if ($reseller_balance_log) {
                        Balance::balanceDeductForUserRecharge('reseller', $reseller_balance_log->reseller_id, -$reseller_balance_log->amount);
                        $resellerBalanceLogReport = ReselleBalanceLogReport::create(
                            [
                                'reseller_id' => $reseller_balance_log->reseller_id,
                                'client_id'   => $client->id,
                                'action'      => 'Customer Deleted',
                                'amount'      => -$reseller_balance_log->amount,
                                'remarks'     => 'Created BY ' . auth()->user()->email,
                                'uniqueId'     => createUUID(),
                                'pop_id'       => $client->pop_id,
                                'commission_amount' => -getCommissionForResellerRecharge($client->id, $reseller_balance_log->amount),
                                'reseller_commission_percentage' => $pop->reseller->commission_percentage,
                                'pop_commission_percentage' => $pop->commission_percentage,
                            ]
                        );
                    }


                    UserAccounting::where('client_id', $client->id)->delete();

                    $income_ids = Billpayment::where('client_id', $client->id)->pluck('income_id')->toArray();

                    if (!empty($income_ids)) {
                        DB::table('incomes')->whereIn('id', $income_ids)->delete();
                    }

                    DB::table('bill_payments')->where('client_id', $client->id)->delete();

                    $sub_reseller_balance_log = DB::table('sub_reseller_balance_log_report')->where('client_id', $client->id)->first();

                    if (!empty($sub_reseller_balance_log)) {

                        Balance::balanceDeductForUserRecharge('pop', $sub_reseller_balance_log->sub_reseller_id, -$sub_reseller_balance_log->amount);

                        SubResellerBalanceLogReport::create(
                            [
                                'reseller_id'       => $sub_reseller_balance_log->reseller_id,
                                'client_id'         => $client->id,
                                'action'            => 'Customer deleted',
                                'amount'            => -$sub_reseller_balance_log->amount,
                                'sub_reseller_id'   => $sub_reseller_balance_log->sub_reseller_id,
                                'remarks'           => 'Created BY ' . auth()->user()->email,
                                'reseller_cost' => -$reseller_balance_log->amount,
                                'commission_amount' => -getCommissionForSubResellerRecharge($client->id, $sub_reseller_balance_log->amount),
                                'reseller_balance_log_id'         => $resellerBalanceLogReport,
                            ]
                        );
                    }

                    // dd($reseller_balance_log);

                    DB::statement("delete from reseller_commission_reference where client_id=$client->id");
                    DB::statement("delete from sub_reseller_commission_reference where client_id=$client->id");
                }

                $deleted = new CustomerDelInfo();
                $deleted->customer_id = $id;
                $deleted->username = $client->userid;
                $deleted->deleted_by = auth()->user()->id;
                //   dd($deleted->customer_id);
                $deleted->save();


                if (checkAPI() && $client->client_approval != 'pending') {
                    $pop = Pop::with("nas")->find($client->pop_id);
                    $mkIp = $pop->nas->nasname;
                    $mkUser = $pop->nas->mikrotick_user;
                    $mkPass = $pop->nas->mikrotick_user_password;
                    $mkPort = $pop->nas->mikrotick_port;
                    $mk = new Mikrotik($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
                    try {
                        $mk->deleteSecret($client->userid);
                    } catch (Exception $e) {
                    }
                }
                DB::commit();

                Artisan::call('cache:clear');
                (new Notification)->notify("..::[Customer Remove]::.. \n Customer Removed.\nRemove By " . auth()->user()->name . " \nCustomer Username : " . $client->userid . " \nPassword : " . $client->password . "\nRemove Time : " . now());
                // return redirect()->route('clients.index')
                //     ->with('success_message', 'Successfully Removed The Customer');
                return response()->json([
                    'status' => 'success',
                    'message' => 'Successfully Removed The Customer',
                ]);
            } catch (\Throwable $th) {
                dd($th);
                DB::rollback();
                // return redirect()->route('clients.index')
                //     ->with('error_message', 'Something is worng');
                return response()->json([
                    'status' => 'error',
                    'message' => 'Something is worng',
                ]);
            }
        } else {
            // return redirect()->route('clients.index')
            //     ->with('error_message', 'Customer already have payment history. please disable the account for future');
            return response()->json([
                'status' => 'error',
                'message' => 'Customer already have payment history. please disable the account for future',
            ]);
        }
    }

    public function newJoin()
    {
        $start = Carbon::parse(today()->firstOfMonth())->format('Y-m-d 00:00:00');

        $end = Carbon::parse(today())->format('Y-m-d 23:59:59');

        $list = Client::list()->whereBetween('created_at', [$start, $end])->orderBy('id', 'desc');

        $marketed_by = ClientReferer::orderBy('firstname', 'asc')->get();

        return view('clients.index', [
            'page_title'    => 'New Join In ',
            'list'          => $list->paginate(500),
            'marketed_by'   => $marketed_by,
            'paginate'      => false,
            'print_url'     => 'newConnectionReport',
            'confday'       => config('app.billing_cycle'),
            'start'         => $start,
            'end'           => $end,
            'reseller'      =>  Reseller::resellerList()->get(),
            'permissions'   =>  Auth::user()->getAllPermissions()->pluck('name')->toArray(),
            'test' => 1,
        ]);
    }

    public function newClientSearchReport(Request $request)
    {

        session()->put('newClientSearchReport', $request->all());


        if (($request->from_date != null) && ($request->to_date != null)) {

            $from = $request->from_date == '' ? today() : Carbon::parse($request->from_date);


            $to   = $request->to_date == '' ? today() : Carbon::parse($request->to_date)->addDay();

            $list = Client::list()->whereBetween('created_at', [$from, $to]);

            if ($request->reseller != 'null' && $request->pop == 'all') {
                if ($request->reseller == "all") {
                    $list;
                } else {
                    // $reseller_ids = DB::table('reseller_user')->where('reseller_id', $request->reseller)->pluck('reseller_id')->toArray();
                    $pop_ids = userPops()->whereIn('reseller_id', userResellers()->where('id', $request->reseller)->pluck('id'))->pluck('id')->toArray();
                    $list->whereIn('pop_id', $pop_ids);
                }
            } elseif ($request->reseller != 'null' && $request->pop != 'null') {
                $list->where('pop_id', $request->pop);
            }

            if ($request->marketed_by != 'null') {
                $list->where('marketed_by', $request->marketed_by);
            }

            if ($request->source_name != 'null') {
                $list->whereHas('clientsinfo', function ($q) use ($request) {
                    $q->where('source_name', $request->source_name);
                });
            }

            $list = $list->orderBy('id', 'desc');

            $export = 'yes';
            return view('clients.customer_search', [
                'list' => $list->paginate(50000),
                'export' => $export,
            ]);
        }
    }

    public function newConnectionReport()
    {

        $request =  session()->get('newClientSearchReport');

        if ($request == null) {
            $list = ClientServices::customerList('newjoin');
        } else {

            $from = $request['from_date'] == '' ? today() : Carbon::parse($request['from_date']);

            $to   = $request['to_date'] == '' ? today() : Carbon::parse($request['to_date'])->addDay();

            $list = Client::list()->whereBetween('created_at', [$from, $to]);

            if ($request['reseller'] != 'null' && $request['pop'] == 'all') {

                $reseller_ids = DB::table('reseller_user')->where('reseller_id', $request['reseller'])->pluck('reseller_id')->toArray();
                $pop_ids = userPops()->whereIn('reseller_id', $reseller_ids)->pluck('id')->toArray();
                $list->whereIn('pop_id', $pop_ids);
            } elseif ($request['reseller'] != 'null' && $request['pop'] != 'null') {
                $list->where('pop_id', $request['pop']);
            }

            if ($request['marketed_by'] != 'null') {
                $list->where('marketed_by', $request['marketed_by']);
            }

            $list = $list->orderBy('id', 'desc');
        }

        return view('clients.newConnectionPrint', [
            'page_title' => 'New Join ',
            'list' => $list->get(),
            'paginate' => false,

        ]);
    }


    public function pendingCustomer()
    {
        $list = ClientServices::customerList('pendingCustomer');

        // dd($list->get());

        return view('clients.index', [
            'page_title' => 'Pending Customer List ',
            'list' => $list->paginate(1000),
            'paginate' => false
        ]);
    }











    public function userDisconnect($id)
    {
        if (checkAPI()) {
            $client = Client::with('pop', 'pop.nas')->where('userid', $id)->first();
            $mkIp = $client->pop->nas->nasname;
            $mkUser = $client->pop->nas->mikrotick_user;
            $mkPass = $client->pop->nas->mikrotick_user_password;
            $mkPort = $client->pop->nas->mikrotick_port;
            try {
                $mk = new Mikrotik($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
                $mk->disconnectSecret($client->userid);
                Toastr::success("client disconnect", 'success');
                return redirect()->back();
            } catch (Exception $err) {
                Toastr::error('something is wrong', 'error');
                return redirect()->back();
            }
        } else {
            $accouting = new Accounting();
            $accouting->singleUserDisconnect($id);
            Toastr::success("client disconnect", 'success');
            return redirect()->back();
        }


        Toastr::error('something is wrong', 'error');

        return redirect()->back();
    }

    public function userDisconnectProcess($id)
    {

        $client = Client::with('pop', 'pop.nas')->where('userid', $id)->first();

        $pop = Pop::find($client->pop_id);
        $nas = Nas::find($pop->nas_id);

        $result = exec('echo User-Name=' . $client->userid . ' | radclient ' . $nas->nasname . ':3799 "disconnect" ' .
            $nas->secret);

        return $result;
    }

    public function recharge(Request $request)
    {
        $clientservice = new ClientServices;
        $status = $clientservice->recharge($request);
        if ($status == 'error') {
            return redirect()->route('clients.index')->with('error_message', 'Not Enough Balance..');
        } elseif ($status == 'success') {
            return redirect()->back()->with('success_message', 'Recharge Successfully');
        }
    }


    public function reactive(Request $request)
    {
        $id = $request->user_approve;
        $user = Client::find($id);

        $expire = ExpireCheck::expire($user->pop_id, $user->package_id, $user->billing_cycle);

        dd($expire);
        dd($user);
    }

    public function onuInformationShow()
    {
        return view("clients.onuPowerList");
    }

    public function onuInformationData()
    {
        // Get user accessible POP IDs (same logic as Client::list())
        $userPopIds = userPops()->pluck('id');

        // Use JOIN for better performance with proper filtering like Client::list()
        $query = OltOnuInformation::select('olt_onu_information.*')
            ->join('clients', 'olt_onu_information.username', '=', 'clients.userid')
            ->whereNotNull('olt_onu_information.username')
            ->where('olt_onu_information.username', '!=', '')
            ->where('clients.client_approval', 'approved') // Only approved clients
            ->whereIn('clients.pop_id', $userPopIds) // Only user's accessible POPs
            ->whereNull('clients.deleted_at'); // Exclude soft deleted clients

        return DataTables::of($query)
            ->editColumn('mac', function ($device) {
                return strtoupper($device->mac);
            })
            ->editColumn('updated_at', function ($device) {
                return $device->updated_at ? $device->updated_at->format('Y-m-d H:i:s') : '';
            })
            ->filterColumn('mac', function ($query, $keyword) {
                // Handle MAC address search with formatted display
                $cleanKeyword = str_replace(':', '', strtoupper($keyword));
                $query->where('olt_onu_information.mac', 'LIKE', "%{$cleanKeyword}%");
            })
            ->rawColumns([])
            ->make(true);
    }

    public function approve(Request $request)
    {
        $id = $request->user_approve;

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

        if (!auth()->user()->can('approve-local-customer') && $user->pop->bill_generate == 'yes') {
            Toastr::error('Not Enough Permission!!');
            return redirect()->back();
        }
        // dd("comes");
        DB::beginTransaction();

        try {

            $user->client_approval = 'approved';
            if (getBillingType() != 'day_to_day') {
                if ($user->expire_date < today()) {
                    $user->clients_status = 'expired';
                } else {
                    $user->clients_status = 'active';
                }
            } else {
                $user->clients_status = ($user->clients_status == 'disable') ? 'deactive' : 'active';
            }
            $user->save();

            dd($user);

            $mk = new SyncWithMk();
            $mk->syncSingleClient($user->id);

            $this->addInRadius($user);

            DB::commit();


            (new Notification)->notify('ID Approved By ' . auth()->user()->name . ' Customer Username : ' . $user->userid . " \nPassword : " . $user->password);


            return redirect()->back()->with('success_message', 'User successfully activated');
        } catch (\Throwable $e) {
            // dd($e);
            DB::rollback();
            Toastr::error($e->getMessage(), 'Failed');
            return back();
        }
    }

    public function addInRadius($user)
    {
        if ($user->ip_address != null && strlen($user->ip_address) == 15) {
            DB::table('radreply')->insert([
                'username'  => $user->userid,
                'attribute' => 'Framed-IP-Address',
                'op'        => ':=',
                'value'     => $user->ip_address
            ]);

            DB::table('radreply')->insert([
                'username'  => $user->userid,
                'attribute' => 'Service-Type',
                'op'        => ':=',
                'value'     => 'Framed-User'
            ]);
        }

        DB::table('radcheck')
            ->updateOrInsert(
                [
                    'username' => $user->userid,
                    'attribute' => 'Cleartext-Password'
                ],
                [
                    'op' => getBillingType() == 'day_to_day' ? '!=' : ':=',
                    'value' => $user->password
                ]
            );

        DB::table('radcheck')
            ->updateOrInsert(
                [
                    'username' => $user->userid,
                    'attribute' => 'NAS-IP-Address'
                ],
                [
                    'op' => getBillingType() == 'day_to_day' ? '!=' : ':=',
                    'value' => $user->pop->nas->nasname
                ]
            );

        DB::table('radusergroup')
            ->updateOrInsert(
                [
                    'username' => $user->userid,
                ],
                [
                    'groupname' => $user->packages->id,
                    'priority' => 1
                ]
            );
    }

    public function checkUsername(Request $request)
    {
        if (request()->ajax()) {
            $username = $request->username;
            if (!checkAPI()) {
                if (preg_match('/[\'^£$%*()}{~?><>,|=+¬]/', $username)) {
                    return false;
                }
                if (preg_match('/^\S.*\s.*\S$/', $username)) {
                    return false;
                }
            }
            $result = Client::withTrashed()->where('userid', $username)
                ->first();

            if (empty($result)) {
                return true;
            } else {
                return false;
            }
        }
    }

    public function checkCustomerCode(Request $request)
    {
        if (request()->ajax()) {
            $customerCode = $request->customerCode;
            if (!checkAPI()) {
                if (preg_match('/[\'^£$%*()}{~?><>,|=+¬]/', $customerCode)) {
                    return false;
                }
                if (preg_match('/^\S.*\s.*\S$/', $customerCode)) {
                    return false;
                }
            }
            $result = Client::withTrashed()->where('customer_code', $customerCode)->first();

            if (empty($result)) {
                return true;
            } else {
                return false;
            }
        }
    }



    public function getResellerBalance($type, $id)
    {
        $balance = Balance::whereType($type)
            ->whereType_id($id)
            ->first();

        if ($balance !== null) {
            return $balance->amount;
        } else {
            return 0;
        }
    }



    public function expireCheck(Request $r)
    {
        return ExpireCheck::expireNew(Pop::find($r->pop), $r->package, $r->billing_cycle);
    }


    public function priceCalculate($day, $price, $total)
    {
        // Validate inputs
        $day = is_numeric($day) ? (float)$day : 0;
        $price = is_numeric($price) ? (float)$price : 0;
        $total = is_numeric($total) ? (float)$total : 0;

        // Prevent division by zero
        if ($day <= 0) {
            return 0;
        }

        return round(($price / $day) * $total);
    }

    public function expireCheckValidation(Request $request)
    {
        if ($request->ajax()) {
            if ($request->billing_cycle) {
                $data = $this->expireCheck($request->billing_cycle);
                $message = $data['exp'] . ' for ' . $data['exp_total'] . ' days will cost BDT ';
                echo $message;
            }
        }
    }



    public function getPackageForPop(Request $request)
    {
        if (request()->ajax()) {
            if ($request->id) {

                $sub_reseller = Pop::find($request->id);


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

                    $list = explode(',', $sub_reseller->sub_package_list);

                    $packages = DB::table('sub_packages')
                        ->whereIn('id', $list)
                        ->get();

                    if ($packages->first()) {

                        $options = '<option>Select a Package</option>';
                        foreach ($packages as $p) {
                            $options .= '<option value="' . $p->id . '">' . $p->name . '</option>';
                        }
                    } else {

                        $options = '<option>No Packages Found</option>';
                    }
                } elseif ($sub_reseller->subreseller == 'no') {

                    $package_list = DB::table('pops')
                        ->join('resellers', 'pops.reseller_id', '=', 'resellers.id')
                        ->select('package_list')
                        ->where('pops.id', '=', $request->id)
                        ->first();

                    $list = explode(',', $package_list->package_list);
                    // dd($list);
                    $packages = DB::table('packages')
                        ->whereIn('id', $list)
                        ->get();

                    if ($packages->first()) {

                        $options = '<option>Select a Package</option>';
                        if (checkSettings('package_price_show_at_client_add') == 'enable') {
                            foreach ($packages as $p) {
                                $options .= '<option value="' . $p->id . '">' . $p->package_name . '--' . $p->package_rate . '</option>';
                            }
                        } else {
                            foreach ($packages as $p) {
                                $options .= '<option value="' . $p->id . '">' . $p->package_name . '</option>';
                            }
                        }
                    } else {

                        $options = '<option>No Packages Found</option>';
                    }
                }



                echo $options;
            }
        }
    }






    public function deactive(Request $request)
    {

        $status = (new ClientActiveDeactiveService)->deactive($request);
        if ($status == 'success') {

            return redirect()->route('clients.index')
                ->with('success_message', 'User deactivated');
        } elseif ($status == 'error') {

            return redirect()->back()
                ->with('error_message', 'Something is wrong. Please Contact with Admin');
        }
    }

    public function reactivate(Request $request)
    {
        $status = (new ClientActiveDeactiveService)->reactivate($request);
        if ($status == 'success') {

            return redirect()->route('clients.index')
                ->with('success_message', 'User reactivated');
        } elseif ($status == 'error') {

            return redirect()->back()
                ->with('error_message', 'Something is wrong. Please Contact with Admin');
        }
    }




    public function getClientDetails(Request $request)
    {

        if ($request->ajax()) {
            if (!empty($request->type) && !empty($request->value) && $request->type != 'batch') {
                // Retrieve the list of POP IDs
                $poplist = Pop::conditionalList();
                $pop_ids = $poplist->pluck('id')->toArray();

                if ($request->type == 'contact_no') {
                    // Handle the search by contact number
                    $Clientsinfo = Clientsinfo::where('contact_no', $request->value)->first();
                    if ($Clientsinfo) {
                        $client_id = $Clientsinfo->client_id;
                        $list = Client::with('clientsinfo', 'pop', 'packages')
                            ->where('id', $client_id)
                            ->whereIn('pop_id', $pop_ids)
                            ->get();
                    } else {
                        $list = null;
                    }
                } else {
                    // Handle the search by other types
                    $list = Client::with('clientsinfo', 'pop', 'packages')
                        ->where($request->type, 'like', $request->value)
                        ->whereIn('pop_id', $pop_ids)
                        ->get();
                }

                if ($list == null) {
                    return '<p class="text-center bg-gray-50 p-2">No User Found</p>';
                }

                $pack = '';
                if ($request->changeType == 'packageChange') {
                    foreach ($list as $item) {
                        if ($item->pop->subreseller == 'yes') {
                            $package_list = $item->pop->sub_package_list;
                            $plist = explode(',', $package_list);
                            $pack = SubPackage::whereIn('id', $plist)->get();
                        } else {
                            $package_list = $item->pop->reseller->package_list;
                            $plist = explode(',', $package_list);
                            $pack = Packages::whereIn('id', $plist)->get();
                        }
                    }
                }

                return view('clients.result', [
                    'r' => $list,
                    'packages' => $pack,
                    'billingCycle' => $this->billingCycle,
                    'confday' => config('app.billing_cycle')
                ]);
            } elseif (!empty($request->reseller)) {
                // Handle the case when reseller information is provided
                $pack = '';
                $poplist = Pop::conditionalList();
                $all_pop_id = $poplist->pluck('id')->toArray();

                $id = auth()->id();
                if (auth()->user()->hasRole('Sub Reseller')) {
                    $pop_ids = DB::table('pop_user')->where('user_id', $id)->pluck('pop_id')->toArray();
                } else {
                    $pop_ids = Pop::where('reseller_id', $request->reseller)->pluck('id')->toArray();
                }

                if ($request->reseller != 'all') {
                    if ($request->pop == 'all') {

                        if ($request->changeType == 'packageChange') {
                            return '<p class="text-center bg-gray-50 p-2 text-danger">Please select a pop...</p>';
                        }

                        $clientList = Client::with('clientsinfo', 'pop', 'packages')->whereIn('pop_id', $pop_ids);

                        if ($request->billing_cycle != null) {
                            $clientList->where('billing_cycle', $request->billing_cycle);
                            if ($request->user_state != null) {
                                $clientList->where('clients_status', $request->user_state);
                            } elseif ($request->user_state == null) {
                                $clientList;
                            }
                        } elseif ($request->billing_cycle == null) {

                            if ($request->user_state != null) {
                                $clientList->where('clients_status', $request->user_state);
                            } elseif ($request->user_state == null) {

                                if ($request->expire_date != null) {
                                    $exp_date = date('Y-m-d', strtotime($request->expire_date));
                                    $clientList->where('expire_date', 'like', $exp_date . '%');
                                } elseif ($request->expire_date == null) {
                                    $clientList;
                                }
                            }
                        }
                        $list = $clientList->get();
                    }

                    if ($request->pop != 'all') {
                        $clientList = Client::with('clientsinfo', 'pop', 'packages')->where('pop_id', $request->pop);
                        if ($request->pack_or_sub_pack != "all") {

                            $pack_pop = Pop::where('id', $request->pop)->first();
                            if ($pack_pop->subreseller == 'yes') {
                                $clientList->where('sub_package_id', $request->pack_or_sub_pack);
                            } elseif ($pack_pop->subreseller != 'yes') {
                                $clientList->where('package_id', $request->pack_or_sub_pack);
                            }

                            if ($request->billing_cycle != null) {
                                $clientList->where('billing_cycle', $request->billing_cycle);
                                if ($request->user_state != null) {
                                    $clientList->where('clients_status', $request->user_state);
                                } elseif ($request->user_state == null) {
                                    $clientList;
                                }
                            } elseif ($request->billing_cycle == null) {
                                if ($request->user_state != null) {
                                    $clientList->where('clients_status', $request->user_state);
                                } elseif ($request->user_state == null) {
                                    if ($request->expire_date != null) {
                                        $exp_date = date('Y-m-d', strtotime($request->expire_date));
                                        $clientList->where('expire_date', 'like', $exp_date . '%');
                                    } elseif ($request->expire_date == null) {
                                        $clientList;
                                    }
                                }
                            }

                            if ($request->area != 'all' && $request->area != null) {
                                $clientList->whereHas('clientsinfo', function ($query) use ($request) {
                                    $query->where('area', $request->area);
                                });
                            }

                            $list = $clientList->get();
                        } elseif ($request->pack_or_sub_pack == "all") {
                            if ($request->billing_cycle != null) {
                                $clientList->where('billing_cycle', $request->billing_cycle);
                                if ($request->user_state != null) {
                                    $clientList->where('clients_status', $request->user_state);
                                } elseif ($request->user_state == null) {
                                    $clientList;
                                }
                            } elseif ($request->billing_cycle == null) {
                                if ($request->user_state != null) {
                                    $clientList->where('clients_status', $request->user_state);
                                } elseif ($request->user_state == null) {

                                    if ($request->expire_date != null) {
                                        $exp_date = date('Y-m-d', strtotime($request->expire_date));
                                        $clientList->where('expire_date', 'like', $exp_date . '%');
                                    } elseif ($request->expire_date == null) {
                                        $clientList;
                                    }
                                }
                            }

                            if ($request->area != 'all' && $request->area != null) {
                                $clientList->whereHas('clientsinfo', function ($query) use ($request) {
                                    $query->where('area', $request->area);
                                });
                            }

                            $list = $clientList->get();
                        }
                    }
                }

                if (empty($list)) {
                    return '<p class="text-center bg-gray-50 p-2 text-danger">No User Found...</p>';
                }

                if ($request->changeType == 'packageChange') {
                    foreach ($list as $item) {
                        if ($item->pop->subreseller == 'yes') {
                            $package_list = $item->pop->sub_package_list;
                            $plist = explode(',', $package_list);
                            $pack = SubPackage::whereIn('id', $plist)->get();
                        } else {
                            $package_list = $item->pop->reseller->package_list;
                            $plist = explode(',', $package_list);
                            $pack = Packages::whereIn('id', $plist)->get();
                        }
                    }
                }

                return view('clients.result_all', [
                    'r' => $list,
                    'packages' => $pack,
                    'billingCycle' => $this->billingCycle,
                    'confday' => config('app.billing_cycle')
                ]);
            } else {
                return '<p class="text-center bg-gray-50 p-2 text-danger">Please select manager and pop...</p>';
            }
        }
    }



    public function expireBillChange($expire_date, $pop, $package, $billing_cycle)
    {


        if ($pop != '' && $package != '' && $billing_cycle != '') {

            $ep = Carbon::createFromFormat($expire_date);

            $pop = Pop::find($pop);
            $curBalance = $this->getResellerBalance('reseller', $pop->reseller_id);

            $dt = Carbon::now();

            $data['exp'] = date($billing_cycle . '-M-Y');
            // $data['exp_total'] = Carbon::parse($currentBillingCycle)->diffInDays($data['exp']);

            if ($dt->day > $billing_cycle) {

                $data['exp'] = Carbon::parse($data['exp'])->addMonth()->format('d-M-Y');
                $data['exp_total'] = Carbon::parse(Carbon::now())->diffInDays($data['exp']);
            }

            $price = Packages::find($package)->package_rate;

            $cost = $this->priceCalculate($dt->daysInMonth, $price, $data['exp_total']);

            // if($cost > $curBalance){
            // return redirect()->back()->with('error_message','Not Enough Balance');
            // }

            $data = array(
                'cost' => $cost,
                'exp_date' => $data['exp'],
                'total_date' => $data['exp_total'],
                'curBalance' => $curBalance
            );


            return $data;
        } else {
            return '';
        }
    }







    public function payment($id)
    {
        $list = ClientServices::customerList('singleUser', $id);
        return view('billing.payment', [
            'list' => $list->get(), //Client::with('clientsinfo','packages','pop')->paginate(5),
            'page_title' => 'View Payment Information',
            'paymenthistory' => Billpayment::with('user')->whereClient_id($id)->get()
        ]);
    }





    public function getResellerPopList(Request $request)
    {
        if (request()->ajax() && !empty($request->id)) {

            $pop = Pop::list()->where('reseller_id', $request->id);

            $option = '<option value="all">All</option>';

            foreach ($pop as $p) {
                $option .= "<option value='" . $p->id . "'>" . $p->popname . "</option>";
            }
            return $option;
        }
    }

    public function getResellPopList(Request $request)
    {
        if (request()->ajax() && !empty($request->id)) {
            $pop = Pop::conditionalList()->where('reseller_id', $request->id);
            $option = '<option value="">Select One</option>';
            foreach ($pop as $p) {
                $option .= "<option value='" . $p->id . "'>" . $p->popname . "</option>";
            }
            echo $option;
        }
    }


    public function loginAttemptsAll(Request $request)
    {


        if (auth()->user()->hasRole(['Reseller Admin', 'Sub Reseller', 'Reseller'])) {

            $list = ClientServices::customerList()->get()->pluck('userid')->toArray();

            $login_attempts =  RadPostAuthFacade::getLoginLogsByUsernames($list);



            return view('login_attempt.index', [
                'login_attempts' => $login_attempts,
                'page_title' => 'Login Attempts'
            ]);
        } else {

            if (!auth()->user()->hasPermissionTo('login-attempts-all')) {
                Toastr::error('Not Enough Permission', 'erro');
                return redirect()->back();
            }

            $login_attempts = RadPostAuthFacade::getAllLoginLogs();

            return view('login_attempt.index', [
                'login_attempts' => $login_attempts,
                'page_title' => 'Login Attempts'
            ]);
        }
    }




    public function query()
    {
        return DB::table('clients')
            ->leftJoin('clientsinfo', 'clientsinfo.client_id', '=', 'clients.id')
            ->leftJoin('packages', 'packages.id', '=', 'clients.package_id')
            ->leftJoin('pops', 'pops.id', '=', 'clients.pop_id')
            ->leftJoin('customer_accounts', 'customer_accounts.client_id', '=', 'clients.id')
            ->leftJoin('bill_generates', 'bill_generates.client_id', '=', 'clients.id')
            ->select(
                'clients.*',
                'customer_accounts.dueAmount',
                'customer_accounts.totalPaid',
                'customer_accounts.totalDiscount',
                'customer_accounts.totalBillAmount',
                'clientsinfo.flat_no',
                'clientsinfo.building_name',
                'clientsinfo.road_no',
                'clientsinfo.block_sector',
                'packages.package_name',
                'pops.popname',
                'clientsinfo.clients_name',
                'clientsinfo.contact_no',
                'clientsinfo.father_name',
                'clientsinfo.mother_name',
                'clientsinfo.area',
                'clientsinfo.email',
                'clientsinfo.national_id',
                'packages.package_rate',
                'billing_type',
                'due_date',
                'bill_generates.created_at as bill_create_date',
                'bill_generates.bill_amount as billamount'
            )
            ->where('clients.clients_status', '!=', 'deactive');
    }

    public function expiredClients(Request $request)
    {


        $type = $request->query('type');

        $list = ClientServices::customerList();


        $list = $list->whereMonth('expire_date', '<=', Carbon::now()->month)
            ->where('clients_status', 'expired');

        if ($type == 'all' || $type == null) {
            // $list->where('pops.id', $type)
            $list->whereMonth('clients.created_at', '=', date('m'))
                ->whereYear('clients.created_at', '=', date('Y'))
                ->orderby('clients.expire_date', 'asc')
                ->orderby('pops.id', 'asc');
        } else {
            $list->where('pops.id', $type)
                ->whereMonth('clients.created_at', '=', date('m'))
                ->whereYear('clients.created_at', '=', date('Y'))
                ->orderby('clients.expire_date', 'asc');
        }
        return view('clients.index', [
            'list' => $list->paginate(1000),
            'page_title' => 'Expired Customer List',
            'poplist' => Pop::all()
        ]);
    }

    public function printExpiredClients(Request $request)
    {

        $list = ClientServices::customerList();

        $type = $request->query('type');
        $list = $list->whereMonth('expire_date', '<=', Carbon::now()->month)
            ->whereMonth('expire_date', '<=', Carbon::now()->month);
        if ($type == 'all' || $type == null) {
            $list->whereMonth('clients.created_at', '=', date('m'))
                ->whereYear('clients.created_at', '=', date('Y'))
                ->orderby('clients.expire_date', 'asc');
        } else {
            $list->where('pops.id', $type)
                ->whereMonth('clients.created_at', '=', date('m'))
                ->whereYear('clients.created_at', '=', date('Y'))
                ->orderby('clients.expire_date', 'asc');
        }
        return view('clients.expiredClientsPrint', [
            'list' => $list->paginate(1000),
            'page_title' => 'Expired Customer List',
            'poplist' => Pop::all()
        ]);
    }




    public function clientSearchBTRC()
    {
        return view('btrcCustomer.index', [
            'page_title' => 'Customer List For BTRC',
            'reseller'   =>  userResellers(),
        ]);
    }

    public function export(Request $request)
    {




        $data[] = '';
        if ($request->reseller_id == 'all') {

            $data = Client::with('clientsinfo')->get();
            return Excel::download(new ClientsExport($data), 'customers.csv');
        } elseif ($request->pop == null && $request->reseller_id != 'all') {

            $pop_ids = userPops()->where('reseller_id', $request->reseller_id)->pluck('id');

            $data = Client::with('clientsinfo')->whereIn('pop_id', $pop_ids)->get();
            return Excel::download(new ClientsExport($data), 'customers.csv');
        } else {

            $data = Client::where('pop_id', $request->pop)->with('clientsinfo', 'packages:id,package_name,package_rate', 'pop:id,popname,reseller_id')->get();
            return Excel::download(new ClientsExport($data), 'customers.csv');
        }
    }

    public function clientNewSearchBTRC()
    {

        return view('btrcCustomer.newIndex', [
            'page_title' => 'Customer New List For BTRC',
            'reseller'   =>  userResellers(),
        ]);
    }

    public function newExport(Request $request)
    {
        $data[] = '';
        $clients = Client::with('clientsinfo', 'clientsinfo.divisions', 'clientsinfo.districts', 'clientsinfo.upazilas', 'clientsinfo.thanas', 'packages:id,package_name,package_rate,package_bandwidth,btrc_package_price', 'pop:id,popname,reseller_id');

        if ($request->user_state != "all") {
            $clients->where('clients_status', $request->user_state);
        }

        if ($request->reseller_id == 'all') {

            $data = $clients->get();
            $fileName = 'BTRC-Report_all.xlsx';
        } elseif (($request->pop == null || $request->pop == 'all') && $request->reseller_id != 'all') {

            $reseller = Reseller::where('id', $request->reseller_id)->first();

            // $pop_ids = userPops()->where('reseller_id', $request->reseller_id)->pluck('id');

            $data = $clients->whereIn('pop_id', userPops()->where('reseller_id', $request->reseller_id)->pluck('id'))->get();
            $fileName = 'BTRC-Report_' . $reseller->name . '.xlsx';

            // return Excel::download(new ClientExportNew($data), 'BTRC-Report_' . $reseller->name . '.xlsx', \Maatwebsite\Excel\Excel::XLSX);
        } elseif ($request->pop != null) {

            $pop = Pop::where('id', $request->pop)->first();

            // $data = Client::where('pop_id', $request->pop)->with('clientsinfo', 'packages:id,package_name,package_rate', 'pop:id,popname,reseller_id')->get();

            $data = $clients->where('pop_id', $request->pop)->get();
            $fileName = 'BTRC-Report_' . $pop->popname . '.xlsx';
            // return Excel::download(new ClientExportNew($data), 'BTRC-Report_' . $pop->popname . '.xlsx', \Maatwebsite\Excel\Excel::XLSX);
        }

        if (globalPermission('mobile_digit_change_on_btrc_export')) {
            foreach ($data as $key => $value) {
                $mobile = $value->clientsinfo->contact_no;
                $mobile = substr_replace($mobile, '1', -6, 1);
                $value->clientsinfo->contact_no = $mobile;
            }
        }

        return Excel::download(new ClientExportNew($data), $fileName, \Maatwebsite\Excel\Excel::XLSX);
    }

    public function dueOtcReport(Request $request)
    {
        $dueOtc = BillGenerate::with('clients', 'clientsinfo')->where('billing_type', 'otc')
            ->whereHas('clientsinfo', function ($q) {
                $q->where('otc_due', '!=', 0);
            })->get();

        return view('report.dueOtc.index', [
            'dueOtc' => $dueOtc
        ]);
    }

    public function totalOtcReport(Request $request)
    {
        $Otc = DB::table('clientsinfo')
            ->leftJoin('clients', 'clients.id', '=', 'clientsinfo.client_id')
            ->select('clientsinfo.*', 'clients.created_at as client_create_date',)
            ->where('clientsinfo.otc', '!=', 0)
            ->get();
        //dd($Otc);

        return view('report.totalOtc.index', [
            'Otc' => $Otc
        ]);
    }

    public function otcReport()
    {
        //dd('hello');
        $start = Carbon::now()->startOfMonth();

        // dd($start);
        $end = today();
        return view('report.totalOtc.index1', [
            'start' => $start,
            'end'   => $end
        ]);
    }

    public function otcSearchResult(Request $request)
    {


        $from = Carbon::parse($request->from_date)->format('Y-m-d 00:00:00');
        $to   = Carbon::parse($request->to_date)->format('Y-m-d 23:59:59');

        $otc_payments = Billpayment::whereHas('income', function ($query) {
            $query->where('incomeHead', '=', '2');
        })->with('clients.clientsinfo', 'income')->whereBetween('created_at', [$from, $to])->where('paid_amount', '>', 0)->get();

        $data = [
            'payments' => $otc_payments
        ];
        // return $data;
        return view('report.totalOtc.result', $data);
    }

    public function mikrotiksSyncClient(Request $request)
    {


        $mikrotick_info = Nas::where('id', $request->mikrotik)->first();


        if (!$mikrotick_info) {
            return response("MikroTik Not Found ", 404);
        }

        $mk = new Mikrotik($mikrotick_info->nasname, $mikrotick_info->mikrotick_user, $mikrotick_info->mikrotick_user_password, $mikrotick_info->mikrotick_port ? (int)$mikrotick_info->mikrotick_port : 8728);


        $response = $mk->getSecret();



        foreach ($response as $key => $value) {

            $client = Client::where('userid', $value['name'])->first();
            $check_mikrotik_client_list = MikcrotikClientList::where('username', $value['name'])->first();

            if ($client == null && $check_mikrotik_client_list == null) {
                $status = 'no';
                if ($value['disabled'] == 'true') {
                    $status = 'yes';
                }
                $mikrotick_client_list = new MikcrotikClientList();
                $mikrotick_client_list->username = $value['name'];
                $mikrotick_client_list->password = $value['password'];
                $mikrotick_client_list->profile_name = $value['profile'];
                $mikrotick_client_list->mk_comment = isset($value['comment']) ? $value['comment'] : '';
                $mikrotick_client_list->disable_status = $status;
                $mikrotick_client_list->static_ip = isset($value['caller-id']) ? $value['caller-id'] : '';
                $mikrotick_client_list->save();
            }
        }
        $data = [
            'client_lists' => MikcrotikClientList::get(),
            'resellers' => Reseller::all(),
            'billing_cycles' => config('app.billing_cycle'),
        ];
        return view('mikrotik.syncList', $data);
    }

    public function saveFromSyncList(Request $request)
    {
        DB::beginTransaction();
        try {
            if (Client::where('userid', $request->userName)->first()) {
                return response("Client Already Exist", 404);
            }
            $expire = date('Y-m-' . $request->billing_cycle . ' 00:00:00');

            $mikrotick_client_list_id = MikcrotikClientList::where('username', $request->userName)->first();

            $client = new Client();
            $client->pop_id = $request->pop;
            $client->billing_cycle = $request->billing_cycle;
            $client->package_id = $request->package;
            $client->userid = trim($request->userName);
            $client->password = trim($request->password);
            $client->expire_date = $expire;
            $client->required_cable = 0;
            $client->created_by = auth()->user()->id;
            $client->client_approval = "pending";
            $client->ip_address = $mikrotick_client_list_id->static_ip ?? "";
            $client->clients_status = $mikrotick_client_list_id->disable_status == "no" ? "deactive" : "disable";

            $client->save();
            $client->customer_id = $client->id;
            $client->save();

            MikcrotikClientList::where('username', $request->userName)->delete();


            $clientInfo = new Clientsinfo();
            $clientInfo->client_id = $client->id;
            $clientInfo->remarks = trim($request->comment);
            $clientInfo->save();
            DB::commit();

            return response("Success", 200);
        } catch (Exception $e) {
            if (Client::where('userid', trim($request->userName))->withTrashed()->first()) {
                return response("User all ready have", 404);
            }
            return response("Error", 404);
        }
    }
    public function reSyncSingleClient(Request $request)
    {

        if (checkAPI()) {
            $clientId = $request->id;
            if (is_nan($clientId)) {
                return back();
            }

            try {
                $syncWithMk = new SyncWithMk();
                $syncWithMk->syncSingleClient($clientId);
                Toastr::success("successfully synchronized client.");
                return back();
            } catch (Exception $err) {
                Toastr::error($err->getMessage());
                return back();
            }
        } else {
            $client = Client::with('pops.nas', 'packages')->where('id', $request->id)->first();
            if ($client) {

                if (globalPermission('RadiusExpiration')) {
                    (new ExpirationService())->syncExpiration($client->userid);
                } else {
                    (new RadiusClientSync())->syncSingleRadiusClient($client->id);
                }
                Toastr::success("successfully synchronized client.");
                return back();
            } else {
                Toastr::success("successfully synchronized client.");
                return back();
            }
        }
    }

    public function neverDisconnectClient(Request $request)
    {
        $logClient = Client::where('id', $request->id)->first();
        $old_client_data = Client::with('clientsinfo')->find($logClient->id);

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

        $new_client_data = Client::with('clientsinfo')->find($logClient->id);
        $this->clientEditLog($logClient, $old_client_data, $new_client_data);

        $request = new Request(['id' => $client->id]);
        $this->reSyncSingleClient($request);

        // if (checkAPI()) {
        //     try {
        //         $syncWithMk = new SyncWithMk();
        //         $syncWithMk->syncSingleClient($client->id);
        //     } catch (Exception $err) {
        //         Toastr::error($err->getMessage());
        //         return back();
        //     }
        // } else {
        //     (new IdEnableDisableController)->enableInRadius($client);
        // }

        Toastr::success("successfully Updated.");
        return back();
    }

    public function syncClientMacToSoftware()
    {
        $allMikrotik = Nas::all();
        $clients = [];
        foreach ($allMikrotik as $mikrotik) {
            $mkIp   = $mikrotik->nasname;
            $mkUser = $mikrotik->mikrotick_user;
            $mkPass = $mikrotik->mikrotick_user_password;
            $mkPort = $mikrotik->mikrotick_port;
            try {
                $mk = new Mikrotik($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
            } catch (Exception $err) {
                continue;
            }
            $mkSecrets = $mk->getSecret();
            $clients = array_merge($clients, $mkSecrets);
        }
        foreach ($clients as $client) {
            if (!array_key_exists("caller-id", $client)) continue;
            if (!filter_var($client["caller-id"], FILTER_VALIDATE_MAC)) continue;
            Client::where("userid", $client["name"])->update([
                "mac" => $client["caller-id"]
            ]);
        }
        return [
            "message" => "mac address successfully synced."
        ];
    }

    public function syncOnlineClientMacToSoftware()
    {
        $allMikrotik = Nas::all();
        $clients = [];
        foreach ($allMikrotik as $mikrotik) {
            $mkIp   = $mikrotik->nasname;
            $mkUser = $mikrotik->mikrotick_user;
            $mkPass = $mikrotik->mikrotick_user_password;
            $mkPort = $mikrotik->mikrotick_port;
            try {
                $mk = new Mikrotik($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
            } catch (Exception $err) {
                continue;
            }
            $mkSecrets = $mk->getActiveConnection();
            $clients = array_merge($clients, $mkSecrets);
        }
        foreach ($clients as $client) {
            if (!array_key_exists("caller-id", $client)) continue;
            if (!filter_var($client["caller-id"], FILTER_VALIDATE_MAC)) continue;
            Client::where("userid", $client["name"])->update([
                "mac" => $client["caller-id"]
            ]);
        }
        return [
            "message" => "mac address successfully synced."
        ];
    }




    public function syncClientIpToSoftware()
    {
        $mks = Nas::all();

        $clients = [];
        foreach ($mks as $mkInfo) {

            $mkIp   = $mkInfo->nasname;
            $mkUser = $mkInfo->mikrotick_user;
            $mkPass = $mkInfo->mikrotick_user_password;
            $mkPort = $mkInfo->mikrotick_port;

            try {
                $mk = new Mikrotik($mkIp, $mkUser, $mkPass, $mkPort ? (int)$mkPort : 8728);
            } catch (Exception $err) {
                continue;
            }

            $mkSecrets = $mk->getSecret();
            $clients = array_merge($clients, $mkSecrets);
        }

        foreach ($clients as $client) {
            if (!array_key_exists("remote-address", $client)) continue;
            if (!filter_var($client["remote-address"], FILTER_VALIDATE_IP)) continue;

            Client::where("userid", $client["name"])->update([
                "ip_address" => $client["remote-address"]
            ]);
        }
        return [
            "message" => "ip address successfully synced"
        ];
    }

    public function clientOnlineIpAddToStaticIp()
    {

        $list = Client::list()->get();

        $online = mikrotikOnlineAndOfflineUsers();

        $syncWithMk = new syncWithMk;

        foreach ($list as $user) {
            if (array_key_exists($user->userid, $online["onlineUsers"])) {
                $ip = $online["onlineUsers"][$user->userid]["address"];
                Client::where('userid', $user->userid)->update([
                    'ip_address' => $ip,
                ]);
                $syncWithMk->syncSingleClient($user->id);
            }
        }
    }

    public function importClinetDue()
    {
        return view('report.import_Clients_due_amount', [
            'page_title' => 'Import Clients Due Amount'
        ]);
    }

    public function importClientsDueAmount(Request $request)
    {
        $list = ClientImportAmountReport::with('client', 'reseller', 'pop')->get();

        if ($request->reseller != 'null') {
            $list = $list->where('reseller_id', $request->reseller);
        }

        if ($request->pop != 'all') {
            $list = $list->where('pop_id', $request->pop);
        }

        if ($request->start_date != null && $request->end_date != null) {
            $list = $list->whereBetween('created_at', [Carbon::parse($request->start_date)->startOfDay(), Carbon::parse($request->end_date)->endOfDay()]);
        }

        return view('report.import_client_due_amount_report', [
            'list' => $list,
            'list_count' => $list->count(),
            'total_due_amount' => $list->sum('due_amount'),
            'total_sub_due_amount' => $list->sum('sub_due_amount'),
            'total_package_amount' => $list->sum('package_amount'),
            'total_sub_package_amount' => $list->sum('sub_package_amount'),
        ]);
    }

    public function clientExceleImport(Request $request)
    {
        $file = $request->file('clientFile')->store('import');
        if ($request->clientFile != null) {
            $fileName = time() . '.' . $request->clientFile->extension();
            $request->clientFile->move(storage_path('app/public/clientFile'), $fileName);
        }

        (new ClientsImport)->import($file);
        Toastr::success("Client File Upload Successfully");
        return back();
    }

    public function clientImport()
    {
        return view('clients.import');
    }

    public function clientImportToCustomer()
    {
        if (!auth()->user()->hasPermissionTo('client-import')) {
            Toastr::error('Not Enough Permission', 'error');
            return redirect()->back();
        }
        return view('clients.clientsimporttocustomer');
    }

    public function storeClientImportToCustomer(Request $request)
    {
        $file = $request->file('clientFile')->store('import');
        if ($request->clientFile != null) {
            $fileName = $request->clientFile->getClientOriginalName() . '_' . date('Y-m-d_H-i-s') . '.' . $request->clientFile->getClientOriginalExtension();
            $request->clientFile->move(storage_path('app/public/clientFile'), $fileName);
        }

        try {
            $import = new ClientsImportToCustomer;
            $import->import($file);

            if ($import->hasErrors()) {
                // Store errors in session and redirect back - transaction was rolled back
                return back()->with([
                    'importErrors' => $import->getErrors(),
                    'successCount' => $import->getSuccessCount(),
                    'showResults' => true,
                    'wasRolledBack' => true
                ]);
            } else {
                Toastr::success("Client File Uploaded Successfully. " . $import->getSuccessCount() . " clients imported.");
                return back();
            }
        } catch (Exception $e) {
            Toastr::error('An unexpected error occurred: ' . $e->getMessage());
            return back();
        }
    }

    public function storeClientDueImportToCustomer(Request $request)
    {
        $file = $request->file('clientDueFile')->store('import');
        if ($request->clientDueFile != null) {
            $fileName = time() . '.' . $request->clientDueFile->extension();
            $request->clientDueFile->move(storage_path('app/public/clientFile'), $fileName);
        }

        DB::beginTransaction();

        try {

            $import = new ClientdueImport;
            $import->import($file);

            DB::commit();

            Toastr::success("Client File Uploaded Successfully");
            return back();
        } catch (\Exception $e) {
            Toastr::error($e->getMessage());
            return back();
        }
    }

    public function clientImportSampleDownload()
    {
        return Excel::download(new ClientsImportSampleFile, 'importfilesample.csv');
    }

    public function clientDueImportSampleDownload()
    {
        return Excel::download(new ClientDueImportSampleFile, 'dueimportfilesample.xlsx');
    }

    public function clientSearchResult(Request $request)
    {

        if (request()->ajax() && !empty($request->id)) {

            $list = Client::list();

            if ($request->id != '') {
                $list->where('userid', 'like', '%' . $request->id . '%');
            }
            $list = $list->skip(0)->take(10)->get();

            return view('clients.topSearchResult', compact('list'));
        }
    }

    public function clientsWithUserName($username)
    {
        $client = Client::where('userid', $username)->first();

        return redirect()->route('clients.show', $client->id);
    }

    public function incomeFix()
    {
        $payment = Billpayment::all();

        $income = Income::all();

        foreach ($payment as $value) {


            if ($value->income_id) {
                $inrow = $income->find($value->income_id)->first();



                // dd($income);
                if ($value->paid_amount != $inrow->amount) {


                    echo $value->paid_amount . ' Income : ' . $inrow->amount;
                    echo ' income id: ' . $value->income_id . ' ' . '<br>';
                    echo '<hr>';

                    $inc = Income::where('id', $value->income_id)
                        ->update([
                            'amount' => $value->paid_amount
                        ]);
                }
            }
        }
    }

    public function clientImportJson()
    {
        return view('clients.importJson');
    }

    public function clientJsonImportSave(Request $request)
    {
        $file = $request->file('clientFile')->store('import');
        if ($request->clientFile != null) {
            $fileName = time() . '.' . $request->clientFile->extension();
            $request->clientFile->move(storage_path('app/public'), $fileName);
        }
        // dd($request->all());
        $path =  Storage::path("/public/${fileName}");

        $data = json_decode(file_get_contents($path), true);
        foreach ($data as $d) {
            // dd($d);
            $package_length = strlen($d["Package"]);
            $reseller_length = strlen($d["Reseller"]);
            $pop_length = strlen($d["POP"]);
            $package = $d["Package"];
            $reseller = $d["Reseller"];
            $pop = $d["POP"];
            $unchange_package = $d["Package"];
            $unchange_reseller = $d["Reseller"];
            $unchange_pop = $d["POP"];
            $space_check_package = 0;
            $space_check_reseller = 0;
            $space_check_pop = 0;


            for ($i = 0; $i < $pop_length; $i++) {
                if ($space_check_pop < 2) {
                    $pop = substr($pop, 1);
                    if ($unchange_pop[$i] == " ") {
                        $space_check_pop++;
                    }
                }
            }

            for ($i = 0; $i < $reseller_length; $i++) {
                if ($space_check_reseller < 2) {
                    $reseller = substr($reseller, 1);
                    if ($unchange_reseller[$i] == " ") {
                        $space_check_reseller++;
                    }
                }
            }

            for ($i = 0; $i < $package_length; $i++) {
                if ($space_check_package < 2) {
                    $package = substr($package, 1);
                    if ($unchange_package[$i] == " ") {
                        $space_check_package++;
                    }
                }
            }


            foreach ($d["Address"] as $add_key => $add_value) {
                dd($add_value);
            }
        }
        dd($data);
        $array = array();

        foreach (explode("<CipherResponse>:", $file) as $key => $line) {
            $array[$key] = $line;
        }
        dd($array);

        return back();
    }

    public function marketingCustomer()
    {
        $start = Carbon::now()->today();
        $end = Carbon::now()->endOfMonth();

        return view('marketing.index', [
            'start' => $start,
            'end' => $end
        ]);
    }

    public function marketingCustomerSearch(Request $request)
    {
        if ($request->ajax()) {

            if (!empty($request->from_date) && !empty($request->to_date)) {

                $from = $request->from_date = '' ? today() : Carbon::parse($request->from_date);
                $to   = $request->to_date = '' ? today() : Carbon::parse($request->to_date)->addDay();
                $marketed_by = Client::groupBy('marketed_by')->pluck('marketed_by')->toArray();

                $user = ClientReferer::with('clients')
                    ->whereHas('clients', function ($q) use ($marketed_by, $from, $to) {
                        $q->whereIn('marketed_by', $marketed_by)
                            ->whereBetween('created_at', [$from, $to]);
                    });
            }

            return view('marketing.result', [
                'user' =>  $user->get(),
            ]);
        }
    }

    public function closeShow($id)
    {
        $list = ClientServices::customerList('singleUser', $id);

        $user = Client::withTrashed()->with('pop.nas')->find($id);
        $pppoe_user = str_replace(' ', '_', $user->userid);

        $accounting = new Accounting();

        $userinfo = $accounting->lastOnlineOfSingleUser($pppoe_user);

        $error = null;
        $bandwidthUsage = null;
        $lastLogoutTime = null;
        if ($userinfo || checkAPI()) {
            $mikrotick_info = checkAPI() ? $user->pop->nas : Nas::where('nasname', $userinfo->nasipaddress)->first();
            if ($mikrotick_info) {
                if ($mikrotick_info->mikrotick_user && $mikrotick_info->mikrotick_user_password) {
                    try {
                        $mk = new Mikrotik($mikrotick_info->nasname, $mikrotick_info->mikrotick_user, $mikrotick_info->mikrotick_user_password, $mikrotick_info->mikrotick_port ? (int)$mikrotick_info->mikrotick_port : 8728);

                        $lastLogoutTime = $mk->getSecret($user->userid)['last-logged-out'];
                        $year = (int)explode(" ", explode("/", $lastLogoutTime)[2])[0];
                        $lastLogoutTime = $year > 2013 ? $lastLogoutTime : "User not connected Yet.";

                        $bandwidthUsage = $mk->getBandwidthUsage($user->userid);
                    } catch (Exception $e) {
                        $error = $e->getMessage();
                    }
                } else {
                    $error = "Mikrotik username or password not provided";
                }
            } else {
                $error = "Mikrotik Not Found";
            }
        } else {
            $error = 'User not Online';
        }
        $customer_payment = CustomerAccount::where('client_id', $id)->count();

        return view('clients.details', [
            'error' => $error,
            'bandwidthUsage' => $bandwidthUsage,
            "lastLogoutTime" => $lastLogoutTime,
            'list' => $list->get(),
            'page_title' => 'Customer Details Information',
            'pop' => Pop::all(),
            'user_id' => auth()->user()->id,
            'customer_account' => $customer_payment,
        ]);
    }

    public function activeCustomer()
    {
        $list = Client::list()->where('clients_status', 'active');
        //dd($list->get());
        return view('clients.active', [
            'page_title' => 'Active Customer List',
            'list'       => $list->paginate(100),
            'reseller'   =>  userResellers(),
            'confday'    => config('app.billing_cycle'),
        ]);
    }

    public function activeCustomerSearch(Request $request)
    {
        if ($request->ajax()) {
            $poplist = Pop::with('reseller')->where('reseller_id', $request->reseller)->get();
            $pop_ids = $poplist->pluck('id')->toArray();
            $pops = Pop::where('id', $request->pop)->get();
            $list[] = '';

            if ($request->reseller != null && $request->pop != null) {
                foreach ($pops as $key => $pop) {
                    $list = Client::list()->where('clients_status', 'active')
                        ->where('pop_id', $pop->id)
                        ->get();
                }
            }
            if ($request->reseller != null && $request->pop == 'all') {
                $list = Client::list()->whereClients_status('active')
                    ->whereIn('pop_id', $pop_ids)
                    ->get();
            }

            return view('clients.customer_search', [
                'list'       =>  $list,
            ]);
        }
    }

    public function storeBandwidthLimit($user)
    {
        $pack_band_limit = $user->packages->limite_quantity ?? 0;
        Client::where('userid', $user->userid)->update(['bandwidth_limit' => $pack_band_limit]);

        return 'success';
    }

    public static function getClientsOnlineInfo($clientsUsernames)
    {
        $onlineResultList = [];
        if (checkAPI()) {
            $online = mikrotikOnlineAndOfflineUsers();
            foreach ($clientsUsernames as $username) {
                if (array_key_exists($username, $online["onlineUsers"])) {
                    $onlineResultList[$username] = "online";
                } else {
                    $onlineResultList[$username] = "offline";
                }
            }
        } else {
            $onlineList = Client::online($clientsUsernames);
            foreach ($clientsUsernames as $username) {
                if (!array_key_exists($username, $onlineList)) {
                    $onlineResultList[$username] = "offline";
                } else {
                    $onlineResultList[$username] = "online";
                }
            }
        }

        return $onlineResultList;
    }

    public function autoDeactiveCheck($user)
    {
        if (checkAPI()) {
            $firstUser = Client::with('pop', 'pop.nas')->where('userid', $user->userid)->first();
            $nasDetail = $firstUser->pop->nas;
            $mkIp = $nasDetail->nasname;
            $mkUsername = $nasDetail->mikrotick_user;
            $mkPassword = $nasDetail->mikrotick_user_password;
            $mkPort = $nasDetail->mikrotick_port;
            $mk = new Mikrotik($mkIp, $mkUsername, $mkPassword, $mkPort ? (int)$mkPort : 8728);

            DB::beginTransaction();
            try {

                $mk->disconnectAndDisableSecret($user->userid);
                $client = Client::with('pop', 'pop.nas')->where('userid', $user->userid)->first();
                $client->update(["clients_status" => "deactive"]);

                DB::commit();
            } catch (Exception $err) {
                DB::rollBack();
            }
        } else {

            DB::beginTransaction();
            try {
                DB::table('clients')
                    ->where('userid', $user->userid)
                    ->update(['clients_status' => 'deactive']);

                DB::table('radcheck')
                    ->where('username', $user->userid)
                    ->update(['op' => '!=']);

                DB::commit();
            } catch (Exception $err) {
                DB::rollBack();
            }
        }

        $deactive_user = Client::where('userid', $user->userid)->first();
        $deactive_user->auto_deactive = NULL;
        $deactive_user->update();

        return 'success';
    }

    public function removeStaticIpBind($clientId)
    {
        $client = Client::with("pop.nas")->find($clientId);
        $client->mac = null;

        $mikrotick_info = $client->pop->nas;
        try {
            $mk = new MikrotikStaticIP($mikrotick_info->nasname, $mikrotick_info->mikrotick_user, $mikrotick_info->mikrotick_user_password, $mikrotick_info->mikrotick_port);

            $arp = $mk->getArpList($client->ip_address);
            if ($arp && $arp["dynamic"] === "false") {
                $mk->deleteArp($client->ip_address);
            }

            $client->save();
            Toastr::success("successfully remove ip binding.");
            return back();
        } catch (\Throwable $th) {
            Toastr::error("something went wrong while unbinding.");
            return back();
        }


        return $client;
    }

    public function slugInsert($user)
    {
        $date = Carbon::now();
        $code = $date->format('YmdHis') . $date->format('v') . Str::random(6);

        $client = Client::where('userid', $user->userid)->first();

        if (empty($client->slug)) {
            if (Client::where('slug', $code)->exists()) {
                $newCode = $date->format('YmdHis') . $date->format('v') . Str::random(6);
                $client->slug = $newCode;
                $client->update();
            } else {
                $client->slug = $code;
                $client->update();
            }
        }

        return 'success';
    }

    public function freeClient()
    {
        $list = Client::list()->where('is_free', 1)->get();
        return view('clients.freeclient', [
            'page_title' => 'Free Customer List',
            'list'       => $list,
            'reseller'   =>  userResellers(),
            'confday'    => config('app.billing_cycle'),
            'total' => $list->count(),
        ]);
    }

    public function freeClientSearch(Request $request)
    {
        if ($request->ajax()) {

            $pops = Pop::with("nas")->where("reseller_id", $request->reseller)->get();

            $clients = Client::list()->where('is_free', 1);

            if ($request->reseller != null) {
                $clients->whereHas('pop', function ($q) use ($pops) {
                    $q->whereIn('id', $pops->pluck('id'));
                });
                if ($request->pop != 'all') {
                    $clients->where('pop_id', $request->pop);
                }
            }

            if ($request->username != null) {
                $clients->where('userid', 'like', '%' . $request->username . '%');
            }




            return view('clients.customer_search', [
                'list'       =>  $clients->get(),
                'total' => $clients->count(),
            ]);
        }
    }

    public function expireDateExtend(Request $request)
    {
        $company_information = CompanyInformation::first();
        $max_extended_day = $company_information->max_extended_day ?? 30;
        // $request->validate([
        //     'payment_dadeline' => "required|numeric|min:0|max:$max_extended_day",
        //     'id' => 'required|exists:clients,id',
        // ]);
        if ($request->payment_dadeline > $max_extended_day) {
            Toastr::error("You can not extend more than " . $max_extended_day . " days.");
            return redirect()->back();
        }

        $old_client = Client::with('clientsinfo')->find($request->id);

        $client = Client::find($request->id);
        $client->payment_dadeline = $request->payment_dadeline;
        $client->update();

        $new_data_client = Client::with('clientsinfo')->find($request->id);
        (new ClientController)->clientEditLog($client, $old_client, $new_data_client);

        if (checkAPI()) {
            $sync = new SyncWithMk();
            $sync->syncSingleClient($client->id);
        }

        Toastr::success("Successfully Changed");
        return redirect()->back();
    }
}
