<?php
// modules/pasarguard/widgets/psg_bulk_edit.php

// ==============================================================
// پردازش AJAX اختصاصی ویجت (فقط اکشن‌های ضروری و سبک)
// ==============================================================
if (basename($_SERVER['PHP_SELF']) == 'psg_bulk_edit.php' && isset($_POST['action'])) {
    ob_start();
    require_once '../../../includes/auth.php';
    if (session_status() === PHP_SESSION_NONE) { session_start(); }
    if (!isAdmin()) { die(json_encode(['success' => false, 'error' => 'Access Denied'])); }
    require_once '../../../config/db.php';
    require_once '../pasarguard_api.php';

    header('Content-Type: application/json');
    ob_clean();
    $action = $_POST['action'];

    // 1. استخراج سریع مپینگ انبار (نقشه طرح‌ها و یوزرها)
    if ($action === 'get_inventory_mapping') {
        global $pdo;
        try {
            $stmt = $pdo->query("SELECT account_username, plan_name FROM inventory");
            $mapping = [];
            while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                $p = $row['plan_name'];
                if (!isset($mapping[$p])) $mapping[$p] = [];
                $mapping[$p][] = $row['account_username'];
            }
            echo json_encode(['success' => true, 'mapping' => $mapping]);
        } catch (Exception $e) {
            echo json_encode(['success' => false, 'error' => 'Database Error']);
        }
        exit;
    }

    // 2. دریافت لیست اکانت‌ها به صورت مینیفای شده (سبک‌ترین حالت ممکن)
    if ($action === 'get_minified_users') {
        $serverId = $_POST['server_id'] ?? null;
        if (!$serverId) { echo json_encode(['success' => false, 'error' => 'سرور مشخص نشده است']); exit; }

        $tokenRes = getPsgApiToken($serverId);
        if (!$tokenRes['success']) { echo json_encode(['success' => false, 'error' => $tokenRes['error']]); exit; }
        
        $token = $tokenRes['token'];
        $serverUrl = $tokenRes['server_url'];

        // دریافت فقط کاربران (حذف پراکسی‌ها و دیتای سنگین V2ray)
        $usersRes = executePsgApiCall($serverUrl, "/api/users?limit=10000", "GET", null, $token);
        $allUsers = $usersRes['data']['users'] ?? ($usersRes['data'] ?? []);
        
        $minifiedUsers = [];
        foreach($allUsers as $u) {
            $minifiedUsers[] = [
                'username' => $u['username'],
                'status' => $u['status'] ?? 'active',
                'data_limit' => isset($u['data_limit']) ? (int)$u['data_limit'] : 0,
                'used_traffic' => isset($u['used_traffic']) ? (int)$u['used_traffic'] : 0,
                'expire' => $u['expire'] ?? null,
                'note' => $u['note'] ?? ''
            ];
        }

        echo json_encode(['success' => true, 'users' => $minifiedUsers]);
        exit;
    }

    // 3. ویرایش هوشمند تکی (Smart Patch) برای استفاده در حلقه
    if ($action === 'bulk_smart_edit') {
        $serverId = $_POST['server_id'] ?? null;
        $username = trim($_POST['username'] ?? '');

        $tokenRes = getPsgApiToken($serverId);
        if (!$tokenRes['success']) { echo json_encode(['success' => false, 'error' => $tokenRes['error']]); exit; }
        
        $token = $tokenRes['token'];
        $serverUrl = $tokenRes['server_url'];

        $current = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "GET", null, $token);
        if ($current['code'] === 200 && isset($current['data']['username'])) {
            $userData = $current['data'];
            
            if (isset($_POST['change_status']) && $_POST['change_status'] === '1') $userData['status'] = trim($_POST['status']);
            if (isset($_POST['change_note']) && $_POST['change_note'] === '1') $userData['note'] = trim($_POST['note']);
            if (isset($_POST['change_reset']) && $_POST['change_reset'] === '1') $userData['data_limit_reset_strategy'] = trim($_POST['reset_strategy']);
            if (isset($_POST['change_limit']) && $_POST['change_limit'] === '1') $userData['data_limit'] = (int)((float)$_POST['data_limit_gb'] * pow(1024, 3));
            
            if (isset($_POST['change_expire']) && $_POST['change_expire'] === '1') {
                $expire = trim($_POST['expire_date']);
                if (empty($expire)) {
                    $userData['expire'] = null;
                } else {
                    date_default_timezone_set('Asia/Tehran');
                    $userData['expire'] = date('Y-m-d\TH:i:sP', strtotime($expire));
                }
            }
            if (isset($_POST['change_proxies']) && $_POST['change_proxies'] === '1') {
                $newProxies = [];
                if (isset($_POST['proxies']) && is_array($_POST['proxies'])) {
                    foreach ($_POST['proxies'] as $proto) {
                        $newProxies[$proto] = isset($userData['proxies'][$proto]) ? $userData['proxies'][$proto] : (($proto === 'shadowsocks') ? ["method" => "chacha20-ietf-poly1305"] : new stdClass());
                    }
                }
                $userData['proxies'] = empty($newProxies) ? new stdClass() : $newProxies;
            }
            if (isset($_POST['change_groups']) && $_POST['change_groups'] === '1') {
                if (isset($_POST['group_ids']) && is_array($_POST['group_ids'])) {
                    $userData['group_ids'] = array_map('intval', array_filter($_POST['group_ids'], 'is_numeric'));
                } else {
                    $userData['group_ids'] = [];
                }
            }

            $res = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "PUT", $userData, $token);
            if ($res['code'] == 200 || $res['code'] == 201 || $res['code'] == 204) {
                echo json_encode(['success' => true, 'username' => $username]);
            } else {
                echo json_encode(['success' => false, 'error' => 'خطای ذخیره‌سازی سرور']);
            }
        } else {
            echo json_encode(['success' => false, 'error' => 'کاربر در سرور یافت نشد.']);
        }
        exit;
    }
}

if (basename($_SERVER['PHP_SELF']) == 'psg_bulk_edit.php') { die('Access Denied'); }

global $pdo;
$serversList = [];
try {
    $serversList = $pdo->query("SELECT * FROM servers ORDER BY id ASC")->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {}
?>

<link rel="stylesheet" type="text/css" href="/vpnet-panel/assets/css/datatables.min.css">
<style>
    .dataTables_wrapper .dataTables_filter input { border: 2px solid #e5e7eb; border-radius: 12px; padding: 6px 12px; outline: none; margin-bottom: 10px; font-size: 12px; }
    html.dark .dataTables_wrapper .dataTables_filter input { background-color: #0f172a; color: #f8fafc; border-color: #334155; }
    .dataTables_wrapper .dataTables_length select { border: 2px solid #e5e7eb; border-radius: 10px; padding: 5px; outline: none; font-size: 12px; }
    html.dark .dataTables_wrapper .dataTables_length select { background-color: #0f172a; color: #f8fafc; border-color: #334155; }
    html.dark .dataTables_wrapper .dataTables_info, html.dark .dataTables_wrapper .dataTables_paginate .paginate_button { color: #94a3b8 !important; }
</style>

<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 mb-10">
    
    <div class="lg:col-span-1 space-y-6">
        
        <div class="bg-white dark:bg-slate-800 rounded-3xl shadow-sm border border-gray-100 dark:border-slate-700 p-6 border-t-8 border-t-blue-500">
            <label class="block text-sm font-black text-gray-800 dark:text-gray-200 mb-3 flex items-center gap-2">
                <svg class="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"></path></svg>
                ۱. انتخاب سرور مبدا
            </label>
            <select id="target_server" onchange="loadServerData()" class="w-full border-2 border-gray-200 dark:border-slate-600 p-3 rounded-xl outline-none focus:border-blue-500 bg-gray-50 dark:bg-slate-700 dark:text-white text-sm font-bold shadow-sm transition">
                <option value="" disabled selected>-- سرور را انتخاب کنید --</option>
                <?php foreach($serversList as $srv): ?>
                    <option value="<?php echo $srv['id']; ?>"><?php echo htmlspecialchars($srv['name']); ?> (<?php echo htmlspecialchars($srv['url']); ?>)</option>
                <?php endforeach; ?>
            </select>
        </div>

        <div class="bg-white dark:bg-slate-800 rounded-3xl shadow-sm border border-gray-100 dark:border-slate-700 p-6 border-t-8 border-t-fuchsia-500">
            <label class="block text-sm font-black text-gray-800 dark:text-gray-200 mb-4 flex items-center gap-2">
                <svg class="w-5 h-5 text-fuchsia-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"></path></svg>
                ۲. فیلترهای ترکیبی
            </label>

            <div class="space-y-4">
                <div>
                    <label class="block text-[11px] font-bold text-gray-500 dark:text-gray-400 mb-1">طرح‌های متصل در انبار</label>
                    <select id="filter_plan" onchange="applyFilters()" class="w-full border border-gray-300 dark:border-slate-600 p-2 rounded-xl outline-none focus:border-fuchsia-500 bg-gray-50 dark:bg-slate-900 text-xs font-bold dark:text-white transition shadow-sm">
                        <option value="all">همه طرح‌ها (بدون فیلتر)</option>
                        </select>
                </div>

                <div>
                    <label class="block text-[11px] font-bold text-gray-500 dark:text-gray-400 mb-1">وضعیت و حجم باقیمانده</label>
                    <select id="filter_status_vol" onchange="applyFilters()" class="w-full border border-gray-300 dark:border-slate-600 p-2 rounded-xl outline-none focus:border-blue-500 bg-gray-50 dark:bg-slate-900 text-xs font-bold dark:text-white transition shadow-sm">
                        <option value="active_50m" selected>فعال > 50 MB باقیمانده</option>
                        <option value="active_10m">فعال > 10 MB باقیمانده</option>
                        <option value="active_30m">فعال > 30 MB باقیمانده</option>
                        <option value="active_100m">فعال > 100 MB باقیمانده</option>
                        <option value="active_200m">فعال > 200 MB باقیمانده</option>
                        <option value="active_unlimited">فعال نامحدود</option>
                        <option value="active_custom">⚙️ ورود دستی حداقل مگابایت...</option>
                        <option value="active_all">همه اکانت‌های فعال</option>
                        <option value="all">همه اکانت‌ها (هر وضعیتی)</option>
                    </select>
                    <div id="custom_vol_container" class="hidden mt-2 flex gap-2">
                        <input type="number" id="custom_vol_mb" placeholder="حداقل MB" value="250" class="w-full border border-gray-300 dark:border-slate-600 p-2 rounded-xl text-xs dark:bg-slate-700 dark:text-white" dir="ltr">
                        <button onclick="applyFilters()" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1.5 rounded-xl text-xs font-bold shrink-0">اعمال</button>
                    </div>
                </div>

                <div>
                    <label class="block text-[11px] font-bold text-gray-500 dark:text-gray-400 mb-1">پرمصرف‌ترین‌ها</label>
                    <select id="filter_top" onchange="applyFilters()" class="w-full border border-gray-300 dark:border-slate-600 p-2 rounded-xl outline-none focus:border-rose-500 bg-gray-50 dark:bg-slate-900 text-xs font-bold dark:text-white transition shadow-sm">
                        <option value="all">-- خاموش --</option>
                        <option value="top_50_limit">۵۰ اکانت محدود پرمصرف</option>
                        <option value="top_50_unlimit">۵۰ اکانت نامحدود پرمصرف</option>
                    </select>
                </div>
            </div>
        </div>

    </div>

    <div class="lg:col-span-3 space-y-6">
        
        <div class="bg-white dark:bg-slate-800 rounded-3xl shadow-sm border border-gray-100 dark:border-slate-700 p-6">
            <h3 class="text-lg font-black text-gray-800 dark:text-white flex items-center gap-2 border-b border-gray-100 dark:border-slate-700 pb-4 mb-5">
                <svg class="w-6 h-6 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path></svg>
                ۳. انتخاب فیلدهای جهت ویرایش
            </h3>
            <p class="text-xs text-gray-500 dark:text-gray-400 font-bold mb-6">ابتدا تیک فیلدهای مورد نظر را بزنید تا روشن شوند. فقط فیلدهای روشن شده ویرایش می‌شوند.</p>
            
            <form id="bulkEditForm" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
                
                <div class="edit-card relative border border-gray-200 dark:border-slate-600 rounded-2xl p-4 transition-colors">
                    <label class="flex items-center gap-2 cursor-pointer mb-3">
                        <input type="checkbox" id="chk_status" onchange="toggleEditGroup(this)" class="w-4 h-4 text-indigo-600 rounded border-gray-300">
                        <span class="text-sm font-bold text-gray-800 dark:text-gray-200">تغییر وضعیت</span>
                    </label>
                    <div class="edit-field-group opacity-40 pointer-events-none transition-opacity">
                        <select id="val_status" class="w-full border border-gray-200 dark:border-slate-600 p-2.5 rounded-xl outline-none text-xs font-bold dark:bg-slate-700 dark:text-white">
                            <option value="active">🟢 فعال (Active)</option>
                            <option value="disabled">🔴 غیرفعال (Disabled)</option>
                            <option value="on_hold">⏳ معلق (On Hold)</option>
                        </select>
                    </div>
                </div>

                <div class="edit-card relative border border-gray-200 dark:border-slate-600 rounded-2xl p-4 transition-colors">
                    <label class="flex items-center gap-2 cursor-pointer mb-3">
                        <input type="checkbox" id="chk_limit" onchange="toggleEditGroup(this)" class="w-4 h-4 text-indigo-600 rounded border-gray-300">
                        <span class="text-sm font-bold text-gray-800 dark:text-gray-200">تغییر حجم مجاز</span>
                    </label>
                    <div class="edit-field-group opacity-40 pointer-events-none transition-opacity">
                        <input type="number" id="val_limit" placeholder="حجم به GB (0 = نامحدود)" class="w-full border border-gray-200 dark:border-slate-600 p-2.5 rounded-xl outline-none text-xs font-bold font-mono dark:bg-slate-700 dark:text-white" dir="ltr">
                    </div>
                </div>

                <div class="edit-card relative border border-gray-200 dark:border-slate-600 rounded-2xl p-4 transition-colors">
                    <label class="flex items-center gap-2 cursor-pointer mb-3">
                        <input type="checkbox" id="chk_expire" onchange="toggleEditGroup(this)" class="w-4 h-4 text-indigo-600 rounded border-gray-300">
                        <span class="text-sm font-bold text-gray-800 dark:text-gray-200">تغییر تاریخ انقضا</span>
                    </label>
                    <div class="edit-field-group opacity-40 pointer-events-none transition-opacity">
                        <input type="datetime-local" id="val_expire" class="w-full border border-gray-200 dark:border-slate-600 p-2 rounded-xl outline-none text-xs font-bold font-mono dark:bg-slate-700 dark:text-white" dir="ltr">
                    </div>
                </div>

                <div class="edit-card relative border border-gray-200 dark:border-slate-600 rounded-2xl p-4 transition-colors">
                    <label class="flex items-center gap-2 cursor-pointer mb-3">
                        <input type="checkbox" id="chk_reset" onchange="toggleEditGroup(this)" class="w-4 h-4 text-indigo-600 rounded border-gray-300">
                        <span class="text-sm font-bold text-gray-800 dark:text-gray-200">قوانین ریست ترافیک</span>
                    </label>
                    <div class="edit-field-group opacity-40 pointer-events-none transition-opacity">
                        <select id="val_reset" class="w-full border border-gray-200 dark:border-slate-600 p-2.5 rounded-xl outline-none text-xs font-bold dark:bg-slate-700 dark:text-white">
                            <option value="no_reset">بدون ریست</option>
                            <option value="day">روزانه</option>
                            <option value="week">هفتگی</option>
                            <option value="month">ماهانه</option>
                            <option value="year">سالانه</option>
                        </select>
                    </div>
                </div>

                <div class="edit-card relative border border-gray-200 dark:border-slate-600 rounded-2xl p-4 transition-colors">
                    <label class="flex items-center gap-2 cursor-pointer mb-3">
                        <input type="checkbox" id="chk_proxies" onchange="toggleEditGroup(this)" class="w-4 h-4 text-indigo-600 rounded border-gray-300">
                        <span class="text-sm font-bold text-gray-800 dark:text-gray-200">تغییر پروتکل‌ها</span>
                    </label>
                    <div class="edit-field-group opacity-40 pointer-events-none transition-opacity flex flex-wrap gap-2 text-[11px] font-mono mt-2">
                        <label class="flex items-center gap-1 cursor-pointer"><input type="checkbox" name="val_proxies[]" value="vless" class="rounded text-indigo-600" checked> vless</label>
                        <label class="flex items-center gap-1 cursor-pointer"><input type="checkbox" name="val_proxies[]" value="vmess" class="rounded text-indigo-600" checked> vmess</label>
                        <label class="flex items-center gap-1 cursor-pointer"><input type="checkbox" name="val_proxies[]" value="trojan" class="rounded text-indigo-600" checked> trojan</label>
                    </div>
                </div>

                <div class="edit-card relative border border-gray-200 dark:border-slate-600 rounded-2xl p-4 transition-colors md:col-span-2 lg:col-span-1">
                    <label class="flex items-center gap-2 cursor-pointer mb-3">
                        <input type="checkbox" id="chk_note" onchange="toggleEditGroup(this)" class="w-4 h-4 text-indigo-600 rounded border-gray-300">
                        <span class="text-sm font-bold text-gray-800 dark:text-gray-200">تغییر یادداشت اکانت</span>
                    </label>
                    <div class="edit-field-group opacity-40 pointer-events-none transition-opacity">
                        <input type="text" id="val_note" placeholder="یادداشت جدید..." class="w-full border border-gray-200 dark:border-slate-600 p-2.5 rounded-xl outline-none text-xs font-bold dark:bg-slate-700 dark:text-white">
                    </div>
                </div>

                <div class="edit-card relative border border-gray-200 dark:border-slate-600 rounded-2xl p-4 md:col-span-2 lg:col-span-3 transition-colors">
                    <label class="flex items-center gap-2 cursor-pointer mb-3">
                        <input type="checkbox" id="chk_groups" onchange="toggleEditGroup(this)" class="w-4 h-4 text-indigo-600 rounded border-gray-300">
                        <span class="text-sm font-bold text-gray-800 dark:text-gray-200">جایگزینی گروه‌ها (Groups)</span>
                    </label>
                    <div class="edit-field-group opacity-40 pointer-events-none transition-opacity">
                        <div id="groups_container" class="flex flex-wrap gap-2 max-h-[150px] overflow-y-auto custom-scrollbar p-3 bg-gray-50 dark:bg-slate-900 rounded-xl border border-gray-200 dark:border-slate-700" dir="ltr">
                            <span class="text-xs text-gray-400 font-bold w-full text-right" dir="rtl">در انتظار انتخاب سرور...</span>
                        </div>
                    </div>
                </div>
                
            </form>
        </div>

        <div id="data_loading" class="hidden bg-white dark:bg-slate-800 rounded-3xl p-16 text-center shadow-sm border border-gray-100 dark:border-slate-700">
            <div class="inline-block animate-spin w-8 h-8 border-4 border-indigo-500 border-t-transparent rounded-full mb-3"></div>
            <p class="text-sm font-bold text-gray-600 dark:text-gray-300" id="loading_msg">در حال ارتباط با سرور...</p>
        </div>

        <div id="table_container" class="hidden bg-white dark:bg-slate-800 rounded-3xl shadow-sm border border-gray-100 dark:border-slate-700 p-6">
            
            <div class="flex justify-between items-center mb-4">
                <h3 class="text-lg font-black text-gray-800 dark:text-white flex items-center gap-2">
                    <svg class="w-5 h-5 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
                    ۴. لیست اکانت‌های فیلتر شده
                </h3>
                <span class="text-xs font-bold bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-400 px-4 py-2 rounded-xl shadow-sm whitespace-nowrap">
                    <span id="selected_users_count" class="font-black text-sm mr-1">0</span> انتخاب شده
                </span>
            </div>

            <div class="overflow-x-auto custom-scrollbar mb-6 border border-gray-100 dark:border-slate-700 rounded-2xl">
                <table id="bulkUsersTable" class="w-full text-left" dir="ltr">
                    <thead>
                        <tr class="text-[11px] text-gray-500 bg-gray-50 dark:bg-slate-900/50 border-b border-gray-200 dark:border-slate-700">
                            <th class="px-4 py-3 font-normal min-w-[200px]"><input type="checkbox" id="selectAllCheckbox" onclick="toggleSelectAll()" class="rounded border-gray-300 mr-2 text-indigo-600 focus:ring-indigo-500 cursor-pointer"> Username</th>
                            <th class="px-4 py-3 font-normal">Status</th>
                            <th class="px-4 py-3 font-normal min-w-[200px]">Data Usage</th>
                            <th class="px-4 py-3 font-normal">Expire</th>
                        </tr>
                    </thead>
                    <tbody id="users_tbody" class="text-sm divide-y divide-gray-100 dark:divide-slate-700/50"></tbody>
                </table>
            </div>

            <div class="flex flex-col sm:flex-row gap-4 mt-6">
                <button type="button" id="btn_test_bulk" onclick="startRun('test')" disabled class="flex-1 bg-white dark:bg-slate-700 border-2 border-indigo-300 dark:border-indigo-600 hover:bg-indigo-50 dark:hover:bg-slate-600 text-indigo-700 dark:text-indigo-300 font-black py-4 rounded-2xl transition shadow-sm disabled:opacity-50 disabled:cursor-not-allowed">
                    🧪 اجرای تستی روی ۲ اکانت
                </button>
                <button type="button" id="btn_start_bulk" onclick="startRun('full')" disabled class="flex-1 bg-indigo-600 hover:bg-indigo-700 text-white font-black py-4 rounded-2xl shadow-lg transition disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2">
                    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
                    اعمال تغییرات روی تمام منتخبین
                </button>
            </div>
        </div>

        <div id="log_section" class="hidden bg-[#0f172a] rounded-3xl p-6 shadow-inner border border-slate-700 h-[300px] overflow-y-auto custom-scrollbar relative">
            <h4 class="text-gray-400 text-xs font-bold mb-4 sticky top-0 bg-[#0f172a] pb-2 border-b border-slate-800 z-10 flex justify-between">
                <span>گزارش لحظه‌ای عملیات (Log)</span>
                <span id="log_counter" class="text-emerald-400">0 پردازش شده</span>
            </h4>
            <div id="log_container" class="space-y-2 font-mono text-[11px] text-gray-300" dir="ltr"></div>
        </div>
    </div>
</div>

<div id="progressOverlay" class="fixed inset-0 bg-slate-900/80 backdrop-blur-sm z-[200] hidden flex-col items-center justify-center p-4 transition-opacity">
    <div class="bg-white dark:bg-slate-800 rounded-3xl p-8 max-w-md w-full shadow-2xl text-center relative overflow-hidden">
        <div class="absolute top-0 left-0 w-full h-1.5 bg-gray-100 dark:bg-slate-700">
            <div id="progressBarTop" class="h-full bg-indigo-500 transition-all duration-300" style="width: 0%"></div>
        </div>
        <div class="w-20 h-20 bg-indigo-50 dark:bg-indigo-900/30 rounded-full flex items-center justify-center mx-auto mb-6">
            <svg class="w-10 h-10 text-indigo-600 dark:text-indigo-400 animate-pulse" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>
        </div>
        <h3 class="text-xl font-black text-gray-800 dark:text-white mb-2">در حال اعمال تغییرات هوشمند...</h3>
        <p id="progressText" class="text-sm font-bold text-gray-500 dark:text-gray-400 mb-8" dir="ltr">Please wait.</p>
        
        <div class="w-full bg-gray-100 dark:bg-slate-700 rounded-full h-4 mb-3 overflow-hidden border border-gray-200 dark:border-slate-600 shadow-inner">
            <div id="progressBar" class="bg-gradient-to-r from-indigo-500 to-purple-600 h-full rounded-full transition-all duration-300 relative" style="width: 0%"></div>
        </div>
        <div class="flex justify-between items-center text-sm font-black text-gray-600 dark:text-gray-300 px-1">
            <span id="progressPercent" class="text-indigo-600 dark:text-indigo-400">0%</span>
            <span id="progressCount" class="font-mono">0 / 0</span>
        </div>
    </div>
</div>

<script src="/vpnet-panel/assets/js/jquery-3.7.0.min.js"></script>
<script src="/vpnet-panel/assets/js/jquery.dataTables.min.js"></script>
<script>
    let dtBulkUsers = null;
    let logProcessedCount = 0;
    
    // متغیرهای دیتابیس لوکال برای فیلتر سریع
    let masterUsersList = []; 
    let inventoryMapping = {}; 

    // متد روشن/خاموش کردن فیلدها با استایل زیبا
    function toggleEditGroup(el) {
        let card = $(el).closest('.edit-card');
        let group = card.find('.edit-field-group');
        if ($(el).is(':checked')) {
            group.removeClass('opacity-40 pointer-events-none');
            card.addClass('bg-indigo-50/50 dark:bg-indigo-900/20 border-indigo-400 dark:border-indigo-600').removeClass('border-gray-200 dark:border-slate-600');
        } else {
            group.addClass('opacity-40 pointer-events-none');
            card.removeClass('bg-indigo-50/50 dark:bg-indigo-900/20 border-indigo-400 dark:border-indigo-600').addClass('border-gray-200 dark:border-slate-600');
        }
    }

    function formatBytesToGB(bytes) { return bytes ? (bytes / (1024 * 1024 * 1024)).toFixed(2) : 0; }
    function formatBytesExact(bytes) {
        if (!+bytes || bytes <= 0) return '0 B';
        const k = 1024, dm = 2, sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
    }
    
    function getStatusBadge(status) {
        if (status === 'active') return `<span class="bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-400 px-2 py-0.5 rounded text-[10px] font-bold">🟢 Active</span>`;
        if (status === 'disabled') return `<span class="bg-rose-100 text-rose-700 dark:bg-rose-900/40 dark:text-rose-400 px-2 py-0.5 rounded text-[10px] font-bold">🔴 Disabled</span>`;
        if (status === 'on_hold') return `<span class="bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-400 px-2 py-0.5 rounded text-[10px] font-bold">⏳ On Hold</span>`;
        if (status === 'expired') return `<span class="bg-gray-200 text-gray-700 dark:bg-slate-700 dark:text-gray-400 px-2 py-0.5 rounded text-[10px] font-bold">⚫ Expired</span>`;
        return status;
    }

    // لود مرحله‌ای برای جلوگیری از گیر کردن سرور
    function loadServerData() {
        let sId = $('#target_server').val();
        if(!sId) return;

        $('#table_container, #log_section').addClass('hidden');
        $('#data_loading').removeClass('hidden');
        $('#loading_msg').text('⏳ در حال اتصال به API و دریافت گروه‌ها...');
        $('#btn_start_bulk, #btn_test_bulk').prop('disabled', true);
        $('#selected_users_count').text('0');

        // مرحله 1: دریافت گروه‌ها (مسیر استاندارد تب کاربران)
        $.post('pasarguard_api.php', { ajax_call: 'groups', server_id: sId }, function(resGroups) {
            
            let groupsList = Array.isArray(resGroups) ? resGroups : (resGroups.data || resGroups.groups || Object.values(resGroups) || []);
            let gHtml = '';
            if(groupsList.length > 0) {
                groupsList.forEach(g => {
                    let gId = typeof g === 'string' ? g : (g.id !== undefined ? g.id : (g.value || ''));
                    let gName = typeof g === 'string' ? g : (g.name || g.title || `Group ${gId}`);
                    if(gId === '') gId = gName;
                    gHtml += `
                    <label class="flex items-center gap-1.5 p-2 bg-white dark:bg-slate-800 rounded-lg cursor-pointer border border-gray-200 dark:border-slate-600 transition hover:bg-indigo-50 dark:hover:bg-slate-700 text-[11px] font-bold text-gray-700 dark:text-gray-300 shadow-sm">
                        <input type="checkbox" name="val_groups[]" value="${gId}" class="rounded text-indigo-600 border-gray-300 focus:ring-indigo-500"> ${gName}
                    </label>`;
                });
            } else {
                gHtml = '<span class="text-rose-500 text-xs font-bold w-full text-center block mt-2">گروهی یافت نشد.</span>';
            }
            $('#groups_container').html(gHtml);

            // مرحله 2: دریافت دیتای انبار (سریع)
            $('#loading_msg').text('⏳ در حال خواندن لیست طرح‌های انبار...');
            $.post('widgets/psg_bulk_edit.php', { action: 'get_inventory_mapping' }, function(resMap) {
                if(resMap && resMap.success) {
                    inventoryMapping = resMap.mapping || {};
                    let planHtml = '<option value="all">همه طرح‌ها (بدون فیلتر)</option>';
                    Object.keys(inventoryMapping).forEach(plan => {
                        planHtml += `<option value="${plan}">📦 کاربران طرح: ${plan}</option>`;
                    });
                    $('#filter_plan').html(planHtml);
                }

                // مرحله 3: دریافت کاربران (مینیفای شده)
                $('#loading_msg').text('⏳ در حال دانلود و بهینه‌سازی لیست کاربران...');
                $.post('widgets/psg_bulk_edit.php', { action: 'get_minified_users', server_id: sId }, function(resUsers) {
                    $('#data_loading').addClass('hidden');
                    if(!resUsers || !resUsers.success) { alert('خطا: ' + (resUsers ? resUsers.error : 'ارتباط قطع شد')); return; }

                    masterUsersList = resUsers.users || [];
                    if (masterUsersList.length === 0) { alert('کاربری در سرور یافت نشد.'); return; }

                    // اجرای فیلتر پیش‌فرض
                    $('#filter_status_vol').val('active_50m');
                    $('#filter_top').val('all');
                    $('#filter_plan').val('all');
                    applyFilters();

                }).fail(function() { $('#data_loading').addClass('hidden'); alert('خطا در دریافت لیست کاربران.'); });
            }).fail(function() { $('#data_loading').addClass('hidden'); alert('خطا در خواندن دیتابیس.'); });
        }).fail(function() { $('#data_loading').addClass('hidden'); alert('خطا در ارتباط با سرور.'); });
    }

    // منطق فیلتر ترکیبی قدرتمند (AND Logic)
    function applyFilters() {
        let filtered = [...masterUsersList];

        // 1. فیلتر طرح انبار
        let plan = $('#filter_plan').val();
        if (plan && plan !== 'all') {
            let planUsers = inventoryMapping[plan] || [];
            filtered = filtered.filter(u => planUsers.includes(u.username));
        }

        // 2. فیلتر وضعیت و حجم
        let sv = $('#filter_status_vol').val();
        if (sv === 'active_custom') { $('#custom_vol_container').removeClass('hidden'); } 
        else { $('#custom_vol_container').addClass('hidden'); }

        if (sv !== 'all') {
            if (sv === 'active_all') {
                filtered = filtered.filter(u => u.status === 'active');
            } else if (sv === 'active_unlimited') {
                filtered = filtered.filter(u => u.status === 'active' && u.data_limit === 0);
            } else {
                let requiredBytes = 0;
                if(sv === 'active_10m') requiredBytes = 10 * 1048576;
                if(sv === 'active_30m') requiredBytes = 30 * 1048576;
                if(sv === 'active_50m') requiredBytes = 50 * 1048576;
                if(sv === 'active_100m') requiredBytes = 100 * 1048576;
                if(sv === 'active_200m') requiredBytes = 200 * 1048576;
                if(sv === 'active_custom') requiredBytes = (parseInt($('#custom_vol_mb').val()) || 0) * 1048576;
                
                filtered = filtered.filter(u => {
                    if (u.status !== 'active') return false;
                    if (u.data_limit === 0) return true; // نامحدود همیشه قبول است
                    let remaining = u.data_limit - (u.used_traffic || 0);
                    return remaining > requiredBytes;
                });
            }
        }

        // 3. فیلتر پرمصرف‌ها (ترتیب و برش)
        let top = $('#filter_top').val();
        if (top === 'top_50_limit') {
            filtered = filtered.filter(u => u.data_limit > 0).sort((a,b) => b.used_traffic - a.used_traffic).slice(0, 50);
        } else if (top === 'top_50_unlimit') {
            filtered = filtered.filter(u => u.data_limit === 0).sort((a,b) => b.used_traffic - a.used_traffic).slice(0, 50);
        }

        renderUsersTable(filtered);
    }

    function renderUsersTable(users) {
        if (dtBulkUsers) { dtBulkUsers.destroy(); }
        
        let html = '';
        users.forEach(user => {
            let limitGB = formatBytesToGB(user.data_limit);
            let usedExact = formatBytesExact(user.used_traffic);
            let percent = (limitGB > 0) ? Math.min(100, Math.round((user.used_traffic / user.data_limit) * 100)) : 0;
            let barColor = percent > 90 ? 'bg-rose-500' : (percent > 70 ? 'bg-amber-500' : 'bg-emerald-500');

            let expireText = '<span class="text-gray-400">نامحدود</span>';
            if (user.expire) {
                let ed = new Date(user.expire);
                expireText = ed.toLocaleDateString('fa-IR') + ' <br><span class="text-[9px] text-gray-500">' + ed.toLocaleTimeString('en-US', {hour12: false}) + '</span>';
            }

            html += `
            <tr class="hover:bg-[#f8fafc] dark:hover:bg-slate-700/30 transition">
                <td class="px-4 py-3">
                    <div class="flex items-center gap-3">
                        <input type="checkbox" class="user-checkbox w-4 h-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 cursor-pointer" value="${user.username}" onchange="updateSelectionCount()">
                        <div class="flex flex-col">
                            <span class="font-bold text-gray-800 dark:text-slate-200 text-xs">${user.username}</span>
                            ${user.note ? `<span class="text-[10px] text-gray-400 truncate max-w-[150px]">${user.note}</span>` : ''}
                        </div>
                    </div>
                </td>
                <td class="px-4 py-3 min-w-[100px]">${getStatusBadge(user.status)}</td>
                <td class="px-4 py-3 min-w-[200px]">
                    <div class="flex flex-col gap-1 w-full">
                        <div class="w-full bg-[#e2e8f0] dark:bg-slate-700 rounded-full h-1.5 overflow-hidden mt-1 shadow-inner">
                            <div class="${user.data_limit === 0 ? 'bg-blue-400' : barColor} h-1.5 rounded-full" style="width: ${user.data_limit === 0 ? 100 : percent}%"></div>
                        </div>
                        <div class="flex justify-between items-center text-[9px] font-bold text-gray-500 mt-1">
                            <span>0 / ${limitGB > 0 ? limitGB + 'G' : '∞'}</span>
                            <span>Tot: ${usedExact}</span>
                        </div>
                    </div>
                </td>
                <td class="px-4 py-3 text-[10px] font-mono">${expireText}</td>
            </tr>`;
        });

        $('#users_tbody').html(html);
        $('#table_container').removeClass('hidden');

        dtBulkUsers = $('#bulkUsersTable').DataTable({ 
            "ordering": false,
            "pageLength": 50,
            "lengthMenu": [[10, 50, 100, 200, 500, -1], [10, 50, 100, 200, 500, "همه"]],
            "language": { 
                "emptyTable": "هیچ کاربری در سرور منطبق با این فیلترها یافت نشد.",
                "sSearch": "جستجوی کاربر:",
                "sLengthMenu": "نمایش _MENU_ سطر",
                "sInfo": "نمایش _START_ تا _END_ از _TOTAL_ اکانت",
                "oPaginate": { "sNext": "بعدی", "sPrevious": "قبلی" }
            },
            dom: '<"flex flex-col md:flex-row justify-between items-center mb-4 gap-4"l<"flex items-center gap-4"f>>rt<"flex flex-col md:flex-row justify-between items-center mt-4 gap-4"ip>'
        });

        $('#selectAllCheckbox').prop('checked', false);
        updateSelectionCount();
    }

    function toggleSelectAll() {
        let isChecked = $('#selectAllCheckbox').prop('checked');
        $('.user-checkbox').prop('checked', isChecked);
        updateSelectionCount();
    }

    function updateSelectionCount() {
        let count = $('.user-checkbox:checked').length;
        $('#selected_users_count').text(count);
        if (count > 0) {
            $('#btn_start_bulk, #btn_test_bulk').prop('disabled', false);
        } else {
            $('#btn_start_bulk, #btn_test_bulk').prop('disabled', true);
        }
    }

    function startRun(runType) {
        let sId = $('#target_server').val();
        
        let selectedUsers = [];
        $('.user-checkbox:checked').each(function() { selectedUsers.push($(this).val()); });
        if(selectedUsers.length === 0) return;

        let reqData = { action: 'bulk_smart_edit', server_id: sId };
        let hasChanges = false;
        
        if($('#chk_status').is(':checked')) { reqData.change_status = '1'; reqData.status = $('#val_status').val(); hasChanges = true; }
        if($('#chk_limit').is(':checked')) { reqData.change_limit = '1'; reqData.data_limit_gb = $('#val_limit').val() || 0; hasChanges = true; }
        if($('#chk_expire').is(':checked')) { reqData.change_expire = '1'; reqData.expire_date = $('#val_expire').val(); hasChanges = true; }
        if($('#chk_reset').is(':checked')) { reqData.change_reset = '1'; reqData.reset_strategy = $('#val_reset').val(); hasChanges = true; }
        if($('#chk_note').is(':checked')) { reqData.change_note = '1'; reqData.note = $('#val_note').val(); hasChanges = true; }
        
        if($('#chk_proxies').is(':checked')) { 
            reqData.change_proxies = '1'; 
            reqData.proxies = [];
            $('input[name="val_proxies[]"]:checked').each(function() { reqData.proxies.push($(this).val()); });
            hasChanges = true; 
        }
        
        if($('#chk_groups').is(':checked')) { 
            reqData.change_groups = '1'; 
            reqData.group_ids = [];
            $('input[name="val_groups[]"]:checked').each(function() { reqData.group_ids.push($(this).val()); });
            hasChanges = true; 
        }

        if(!hasChanges) {
            alert('شما هیچ فیلدی را برای ویرایش تیک نزده‌اید!');
            return;
        }

        let queue = [];
        if (runType === 'test') {
            queue = selectedUsers.slice(0, 2);
            if(!confirm(`آیا از اعمال این تغییرات روی ${queue.length} کاربر اول جهت تست مطمئن هستید؟`)) return;
        } else {
            queue = selectedUsers;
            if(!confirm(`آیا از اعمال این تغییرات روی تمام ${queue.length} کاربر انتخاب شده مطمئن هستید؟`)) return;
        }

        processQueue(queue, reqData);
    }

    async function processQueue(queue, baseReqData) {
        $('#log_section').removeClass('hidden');
        $('#progressOverlay').removeClass('hidden').addClass('flex');
        $('#progressCount').text(`0 / ${queue.length}`);
        $('#progressBar, #progressBarTop').css('width', '0%');
        $('#progressPercent').text('0%');
        
        $('#btn_start_bulk, #btn_test_bulk').prop('disabled', true);
        logProcessedCount = 0;
        $('#log_container').html('');

        for(let i = 0; i < queue.length; i++) {
            let uname = queue[i];
            $('#progressText').html(`Updating: <span class="text-indigo-600 font-mono text-lg ml-2">${uname}</span>`);
            
            let currentData = { ...baseReqData, username: uname };

            try {
                let response = await $.ajax({
                    url: 'widgets/psg_bulk_edit.php',
                    type: 'POST',
                    dataType: 'json',
                    data: currentData
                });

                if(response && response.success) {
                    logMessage(`<span class="text-emerald-400">[SUCCESS]</span> ${uname} updated.`);
                    $(`.user-checkbox[value="${uname}"]`).prop('checked', false);
                } else {
                    let err = response ? response.error : 'Unknown Error';
                    logMessage(`<span class="text-rose-400">[ERROR]</span> ${uname} - ${err}`);
                }
            } catch (err) {
                logMessage(`<span class="text-rose-400">[FAILED]</span> ${uname} - Network Timeout.`);
            }

            let percent = Math.round(((i + 1) / queue.length) * 100);
            $('#progressBar, #progressBarTop').css('width', percent + '%');
            $('#progressPercent').text(percent + '%');
            $('#progressCount').text(`${i + 1} / ${queue.length}`);
            
            await new Promise(r => setTimeout(r, 100));
        }

        setTimeout(() => {
            $('#progressOverlay').addClass('hidden').removeClass('flex');
            updateSelectionCount();
            alert('پردازش گروهی به اتمام رسید. لطفا جدول لاگ را بررسی کنید.');
        }, 800);
    }

    function logMessage(htmlMsg) {
        logProcessedCount++;
        $('#log_counter').text(`${logProcessedCount} پردازش شد`);
        let time = new Date().toLocaleTimeString('en-US', { hour12: false });
        $('#log_container').append(`<div><span class="text-gray-500">[${time}]</span> ${htmlMsg}</div>`);
        let logSec = document.getElementById('log_section');
        logSec.scrollTop = logSec.scrollHeight;
    }
</script>