<?php
/**
 * WizWiz — X-UI Sanaei → Pasarguard Migration Tool
 * Single-file, self-contained.  Place in wizpanel/ (or any web-accessible dir).
 *
 * Sub-link strategy:
 *   X-UI users have a subId token  →  we pass sub_id=<token> to Pasarguard
 *   Both panels then share the exact same /sub/<token> path.
 *   Only the base domain needs to match (or be pointed there).
 */
declare(strict_types=1);
ob_start();
ini_set('display_errors', '0');
error_reporting(0);
session_start();

// ── service auto-loader ──────────────────────────────────────────────────────
$_svcRoot = __DIR__ . '/../wizwizxui-timebot/services';
$_loadErrors = [];
foreach ([
    'XuiV3Config', 'XuiV3ApiClient', 'XuiV3Service',
    'PasarguardApiClient', 'PasarguardConfig', 'PasarguardService',
] as $_cls) {
    $f = $_svcRoot . '/' . $_cls . '.php';
    if (!class_exists($_cls)) {
        if (file_exists($f)) {
            require_once $f;
        } else {
            $_loadErrors[] = "فایل یافت نشد: $f";
        }
    }
}

// ── helper: safe JSON response ───────────────────────────────────────────────
function jsonOut(array $data): void
{
    ob_end_clean();
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($data, JSON_UNESCAPED_UNICODE);
    exit;
}

// ── AJAX action dispatcher ───────────────────────────────────────────────────
$action = $_GET['action'] ?? $_POST['action'] ?? '';

if ($action === 'test_xui') {
    if (!class_exists('XuiV3ApiClient')) {
        jsonOut(['ok' => false, 'msg' => 'کلاس XuiV3ApiClient بارگذاری نشد. مسیر سرویس‌ها را بررسی کنید. ' . implode(' | ', $_loadErrors)]);
    }
    try {
        $cfg    = buildXuiConfig($_POST);
        $client = new XuiV3ApiClient($cfg);
        $r      = $client->listInbounds();
        jsonOut(['ok' => $r->success, 'msg' => $r->success ? 'اتصال موفق ✓' : (string)($r->msg ?? 'خطا')]);
    } catch (Throwable $e) {
        jsonOut(['ok' => false, 'msg' => 'خطا: ' . $e->getMessage()]);
    }
}

if ($action === 'test_pg') {
    if (!class_exists('PasarguardApiClient')) {
        jsonOut(['ok' => false, 'msg' => 'کلاس PasarguardApiClient بارگذاری نشد. ' . implode(' | ', $_loadErrors)]);
    }
    try {
        $r = PasarguardApiClient::probeConnection(
            trim($_POST['pg_url']  ?? ''),
            trim($_POST['pg_user'] ?? ''),
            trim($_POST['pg_pass'] ?? '')
        );
        jsonOut(['ok' => $r['success'], 'msg' => $r['success'] ? 'اتصال موفق ✓' : $r['msg']]);
    } catch (Throwable $e) {
        jsonOut(['ok' => false, 'msg' => 'خطا: ' . $e->getMessage()]);
    }
}

if ($action === 'fetch_pg_groups') {
    if (!class_exists('PasarguardService')) {
        jsonOut(['ok' => false, 'groups' => [], 'msg' => 'کلاس PasarguardService بارگذاری نشد.']);
    }
    try {
        $svc = new PasarguardService([
            'panel_url' => trim($_POST['pg_url']  ?? ''),
            'username'  => trim($_POST['pg_user'] ?? ''),
            'password'  => trim($_POST['pg_pass'] ?? ''),
            'type'      => 'pasarguard',
        ]);
        $groups = $svc->listGroups();
        $list = [];
        foreach ($groups as $g) {
            $gid = (int) ($g->id ?? 0);
            if ($gid <= 0) continue;
            $list[] = ['id' => $gid, 'name' => trim((string) ($g->title ?? $g->name ?? 'Group #' . $gid))];
        }
        jsonOut(['ok' => !empty($list), 'groups' => $list, 'msg' => empty($list) ? 'گروهی یافت نشد' : '']);
    } catch (Throwable $e) {
        jsonOut(['ok' => false, 'groups' => [], 'msg' => 'خطا: ' . $e->getMessage()]);
    }
}

if ($action === 'load_users') {
    if (!class_exists('XuiV3ApiClient')) {
        jsonOut(['ok' => false, 'msg' => 'کلاس XuiV3ApiClient بارگذاری نشد. ' . implode(' | ', $_loadErrors)]);
    }
    try {
        $xuiInput = $_POST['xui'] ?? [];
        $pgInput  = $_POST['pg']  ?? [];
        if (is_string($xuiInput)) $xuiInput = json_decode($xuiInput, true) ?: [];
        if (is_string($pgInput))  $pgInput  = json_decode($pgInput,  true) ?: [];
        $_SESSION['mig_xui'] = $xuiInput;
        $_SESSION['mig_pg']  = $pgInput;

        $cfg    = buildXuiConfig($xuiInput);
        $client = new XuiV3ApiClient($cfg);
        $r      = $client->listClients();
        if (!$r->success) {
            jsonOut(['ok' => false, 'msg' => (string)($r->msg ?? 'خطا در دریافت کاربران')]);
        }
        $raw   = is_array($r->obj) ? $r->obj : [];
        $users = [];
        foreach ($raw as $u) {
            $up         = (int) ($u->up      ?? 0);
            $down       = (int) ($u->down    ?? 0);
            $totalBytes = (int) ($u->totalGB ?? $u->total ?? 0); // X-UI stores bytes in this field (despite the "GB" name)
            $used       = $up + $down;
            $remBytes   = max(0, $totalBytes - $used);
            // If totalBytes=0 it means unlimited; we'll treat as unlimited (0 = no limit in Pasarguard)
            $remGB      = $totalBytes > 0 ? round($remBytes / 1073741824, 2) : 0;
            // expiryTime can be in seconds, ms, or even μs depending on the X-UI version/fork
            // Normalize by dividing by 1000 until we're in a plausible seconds range (before year 2200)
            $expiryRaw  = (int) ($u->expiryTime ?? 0);
            $expirySec  = $expiryRaw;
            while ($expirySec > 4102444800 && $expirySec > 0) { // 4102444800 = year 2100
                $expirySec = (int)($expirySec / 1000);
            }
            $remDays    = $expirySec > 0 ? max(0, (int) ceil(($expirySec - time()) / 86400)) : 0;
            $subId      = (string) ($u->subId ?? $u->email ?? '');
            $xuiSub     = buildXuiSubLink($xuiInput, $subId);
            $users[]    = [
                'email'   => (string) ($u->email ?? ''),
                'subId'   => $subId,
                'remGB'   => $remGB,
                'remDays' => $remDays,
                'enable'  => (bool) ($u->enable ?? true),
                'xuiSub'  => $xuiSub,
            ];
        }
        $_SESSION['mig_users'] = $users;
        jsonOut(['ok' => true, 'users' => $users, 'count' => count($users)]);
    } catch (Throwable $e) {
        jsonOut(['ok' => false, 'msg' => 'خطا: ' . $e->getMessage()]);
    }
}

if ($action === 'migrate_one') {
    if (!class_exists('PasarguardService')) {
        jsonOut(['ok' => false, 'msg' => 'کلاس PasarguardService بارگذاری نشد.']);
    }
    try {
        $email = trim($_POST['email'] ?? '');
        if ($email === '' || empty($_SESSION['mig_users']) || empty($_SESSION['mig_pg'])) {
            jsonOut(['ok' => false, 'msg' => 'نشست منقضی شده، صفحه را رفرش کنید']);
        }
        $userData = null;
        foreach ($_SESSION['mig_users'] as $u) {
            if ($u['email'] === $email) { $userData = $u; break; }
        }
        if (!$userData) {
            jsonOut(['ok' => false, 'msg' => "کاربر '$email' در نشست یافت نشد"]);
        }

        $pgCfg   = $_SESSION['mig_pg'];
        $svc     = new PasarguardService([
            'panel_url' => trim($pgCfg['url']  ?? ''),
            'username'  => trim($pgCfg['user'] ?? ''),
            'password'  => trim($pgCfg['pass'] ?? ''),
            'type'      => 'pasarguard',
        ]);
        $groupId  = (int) ($pgCfg['group_id'] ?? 0);

        $remGB    = (float) $userData['remGB'];
        $remDays  = (int)   $userData['remDays'];

        // remGB=0 means unlimited in X-UI → send 0 to Pasarguard (unlimited)
        // remDays=0 means no expiry → send 0 (no expiry)
        $volumeGb = $remGB  > 0 ? (int) ceil($remGB)  : 0;
        $days     = $remDays > 0 ? $remDays             : 0;

        // Create user on Pasarguard; if username already exists, retry with _new suffix
        $usedEmail = $email;
        $res = $svc->createUserWithGroup($usedEmail, $volumeGb, $days, $groupId);
        if (!$res->success) {
            $errMsg = strtolower((string)($res->msg ?? ''));
            $isExists = strpos($errMsg, 'exist') !== false
                     || strpos($errMsg, 'already') !== false
                     || strpos($errMsg, 'duplicate') !== false
                     || strpos($errMsg, 'taken') !== false;
            if ($isExists) {
                // Retry with _new suffix to avoid collision
                $usedEmail = $email . '_new';
                $res = $svc->createUserWithGroup($usedEmail, $volumeGb, $days, $groupId);
            }
            if (!$res->success) {
                jsonOut(['ok' => false, 'email' => $email, 'msg' => (string)($res->msg ?? 'ساخت کاربر ناموفق بود')]);
            }
        }

        // Get the actual Pasarguard sub URL (the panel assigns its own token)
        $pgBase   = rtrim(trim($pgCfg['url'] ?? ''), '/');
        $pgSub    = (string) ($res->vray_links[0] ?? '');
        if ($pgSub === '' || !preg_match('~^https?://~i', $pgSub)) {
            $fresh = $svc->getUser($usedEmail);
            if (is_object($fresh)) {
                $rawSubUrl = (string) ($fresh->subscription_url ?? '');
                $pgSub     = PasarguardConfig::buildSubscriptionUrl($pgBase, $rawSubUrl);
            }
        }

        // Old X-UI sub URL for this user
        $xuiSub   = (string) ($userData['xuiSub'] ?? '');
        $xuiSubId = (string) ($userData['subId']  ?? '');

        // Save redirect mapping: old_sub_token → new Pasarguard full sub URL
        if (!isset($_SESSION['mig_redirects'])) {
            $_SESSION['mig_redirects'] = [];
        }
        if ($xuiSubId !== '' && $pgSub !== '') {
            $_SESSION['mig_redirects'][$xuiSubId] = $pgSub;
        }

        // Include rename note if we used _new suffix
        $note = ($usedEmail !== $email) ? " (نام تغییر یافت به: $usedEmail)" : '';

        jsonOut([
            'ok'         => true,
            'email'      => $email,
            'pgUsername' => $usedEmail,
            'xuiSub'     => $xuiSub,
            'pgSub'      => $pgSub,
            'note'       => $note,
            'msg'        => '',
        ]);
    } catch (Throwable $e) {
        jsonOut(['ok' => false, 'email' => ($_POST['email'] ?? ''), 'msg' => 'خطا: ' . $e->getMessage()]);
    }
}

// ── Generate redirect files for shared hosting ───────────────────────────────
if ($action === 'get_redirect_files') {
    $redirects = $_SESSION['mig_redirects'] ?? [];
    if (empty($redirects)) {
        jsonOut(['ok' => false, 'msg' => 'هنوز مهاجرتی انجام نشده']);
    }

    // Build PHP forwarder content
    $mapLines = '';
    foreach ($redirects as $oldToken => $newUrl) {
        $mapLines .= "    " . var_export($oldToken, true) . " => " . var_export($newUrl, true) . ",\n";
    }
    $phpContent = '<?php
/**
 * WizWiz Sub Forwarder
 * آپلود این فایل و .htaccess مقابلش را در ریشه هاست Sub قدیمی خود قرار دهید.
 * هر درخواست /sub/OLD_TOKEN به /sub/NEW_PG_TOKEN پنل پاسارگارد هدایت می‌شود.
 */
$map = [
' . $mapLines . '];

$token = $_GET[\'t\'] ?? trim($_SERVER[\'PATH_INFO\'] ?? \'\', \'/\');
// strip leading "sub/" if present
$token = preg_replace(\'~^sub/~\', \'\', $token);

if (isset($map[$token])) {
    header(\'Location: \' . $map[$token], true, 301);
    exit;
}
http_response_code(404);
echo "Sub not found.";
';

    // Build .htaccess content
    $htaccess = 'RewriteEngine On

# Forward old X-UI sub requests to Pasarguard via the forwarder script
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^sub/(.+)$ /xui_sub_forwarder.php?t=$1 [QSA,L]
';

    jsonOut([
        'ok'        => true,
        'php'       => $phpContent,
        'htaccess'  => $htaccess,
        'count'     => count($redirects),
    ]);
}

// ── helpers ──────────────────────────────────────────────────────────────────
function buildXuiConfig(array $p): array
{
    return [
        'base_url'              => trim($p['url']   ?? ''),
        'username'              => trim($p['user']  ?? ''),
        'password'              => trim($p['pass']  ?? ''),
        'api_token'             => trim($p['token'] ?? ''),
        'auth_mode'             => 'auto',
        'subscription_base_url' => trim($p['sub_url']  ?? ''),
        'sub_path'              => trim($p['sub_path'] ?? '/sub/'),
        'xui_v3_enabled'        => true,
    ];
}
function buildXuiSubLink(array $p, string $subId): string
{
    if ($subId === '') return '';
    $base = rtrim(trim($p['sub_url'] ?? $p['url'] ?? ''), '/');
    $path = '/' . ltrim(trim($p['sub_path'] ?? '/sub/'), '/');
    return $base . $path . $subId;
}
?>
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>مهاجرت X-UI → Pasarguard</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
  body{font-family:Tahoma,Arial,sans-serif;background:#f0f4f8}
  .card{background:#fff;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,.08);padding:24px;margin-bottom:20px}
  .step-dot{width:32px;height:32px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-weight:bold;font-size:13px}
  .step-done{background:#22c55e;color:#fff}
  .step-active{background:#6366f1;color:#fff}
  .step-pending{background:#e2e8f0;color:#94a3b8}
  .progress-bar{height:10px;background:#e2e8f0;border-radius:5px;overflow:hidden}
  .progress-fill{height:100%;background:linear-gradient(90deg,#6366f1,#8b5cf6);border-radius:5px;transition:width .4s}
  .badge-ok  {background:#dcfce7;color:#16a34a;padding:2px 8px;border-radius:20px;font-size:11px}
  .badge-err {background:#fee2e2;color:#dc2626;padding:2px 8px;border-radius:20px;font-size:11px}
  .badge-warn{background:#fef3c7;color:#d97706;padding:2px 8px;border-radius:20px;font-size:11px}
  .log-box{background:#0f172a;color:#e2e8f0;font-size:12px;border-radius:8px;padding:12px;height:280px;overflow-y:auto;font-family:monospace;line-height:1.6}
  .log-ok{color:#4ade80}.log-err{color:#f87171}.log-info{color:#93c5fd}.log-warn{color:#fbbf24}
  input,select{border:1px solid #cbd5e1;border-radius:8px;padding:8px 12px;width:100%;font-size:13px;background:#f8fafc}
  input:focus,select:focus{outline:none;border-color:#6366f1;box-shadow:0 0 0 3px rgba(99,102,241,.15)}
  .btn{border-radius:8px;padding:8px 20px;font-size:13px;font-weight:600;cursor:pointer;border:none;transition:all .2s}
  .btn:disabled{opacity:.45;cursor:not-allowed}
  .btn-primary{background:#6366f1;color:#fff}.btn-primary:hover:not(:disabled){background:#4f46e5}
  .btn-green{background:#22c55e;color:#fff}.btn-green:hover:not(:disabled){background:#16a34a}
  .btn-gray{background:#e2e8f0;color:#475569}.btn-gray:hover:not(:disabled){background:#cbd5e1}
  th{background:#f1f5f9;font-size:12px;color:#475569;padding:8px 10px;text-align:right;white-space:nowrap}
  td{padding:7px 10px;font-size:12px;border-bottom:1px solid #f1f5f9;vertical-align:middle}
  .hidden{display:none}
  .field-group{display:grid;grid-template-columns:1fr 1fr;gap:10px}
  @media(max-width:600px){.field-group{grid-template-columns:1fr}}
  .info-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:12px}
  .warn-box{background:#fef3c7;border:1px solid #fcd34d;border-radius:10px;padding:12px}
  code{background:#f1f5f9;padding:2px 6px;border-radius:4px;font-size:11px;direction:ltr;display:inline-block}
</style>
</head>
<body class="p-4 md:p-8">
<div style="max-width:960px;margin:0 auto">

<!-- Header -->
<div class="card" style="background:linear-gradient(135deg,#6366f1,#8b5cf6);color:#fff;padding:20px 24px;margin-bottom:20px">
  <div style="display:flex;align-items:center;gap:12px">
    <svg width="36" height="36" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
      <path stroke-linecap="round" stroke-linejoin="round" d="M7.5 21 3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5 4.5 4.5m0 0L16.5 12M21 7.5H7.5"/>
    </svg>
    <div>
      <h1 style="font-size:20px;font-weight:700;margin:0">ابزار مهاجرت X-UI → Pasarguard</h1>
      <p style="font-size:12px;opacity:.85;margin:4px 0 0">انتقال کاربران با حجم و مدت باقیمانده • حفظ کامل لینک سابسکریپشن</p>
    </div>
  </div>
</div>

<!-- Step indicator -->
<div class="card" style="padding:14px 20px;margin-bottom:20px">
  <div style="display:flex;align-items:center;gap:6px;flex-wrap:wrap">
    <span id="dot1" class="step-dot step-active">۱</span>
    <span style="font-size:12px;color:#475569;margin-left:2px">تنظیمات</span>
    <div style="flex:1;height:2px;background:#e2e8f0;min-width:16px"></div>
    <span id="dot2" class="step-dot step-pending">۲</span>
    <span style="font-size:12px;color:#475569;margin-left:2px">پیش‌نمایش</span>
    <div style="flex:1;height:2px;background:#e2e8f0;min-width:16px"></div>
    <span id="dot3" class="step-dot step-pending">۳</span>
    <span style="font-size:12px;color:#475569;margin-left:2px">مهاجرت</span>
    <div style="flex:1;height:2px;background:#e2e8f0;min-width:16px"></div>
    <span id="dot4" class="step-dot step-pending">۴</span>
    <span style="font-size:12px;color:#475569;margin-left:2px">گزارش</span>
  </div>
</div>

<!-- ══════════════ STEP 1: CONFIG ══════════════ -->
<div id="step1" class="card">
  <h2 style="font-size:15px;font-weight:700;color:#1e293b;margin-bottom:4px">⚙️ مرحله ۱: تنظیمات اتصال</h2>
  <p style="font-size:12px;color:#64748b;margin-bottom:16px">اطلاعات هر دو پنل را وارد کنید</p>

  <!-- How it works -->
  <div class="info-box" style="margin-bottom:16px">
    <p style="font-size:12px;color:#1e40af;margin:0">
      <strong>🔑 روش حفظ لینک سابسکریپشن (دو مرحله‌ای):</strong><br/>
      ① ابتدا کاربر در Pasarguard ساخته می‌شود.<br/>
      ② بلافاصله با یک درخواست <code>PUT /api/user/{username}</code> با پارامتر <code>sub_id</code>،
      همان token دقیق X-UI روی کاربر جدید اعمال می‌شود.<br/>
      نتیجه: <strong>مسیر <code>/sub/TOKEN</code> در هر دو پنل کاملاً یکسان است</strong>.
      کافی است دامنه Sub URL هر دو پنل یکسان باشد (یا به یک IP اشاره کند).
    </p>
  </div>

  <!-- X-UI -->
  <div style="background:#f0f4ff;border:1px solid #c7d2fe;border-radius:10px;padding:16px;margin-bottom:16px">
    <h3 style="font-size:13px;font-weight:700;color:#4f46e5;margin-bottom:12px">🔵 پنل X-UI (سنایی) — منبع</h3>
    <div class="field-group">
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">آدرس پنل</label>
        <input id="xui_url" type="url" placeholder="https://panel.example.com:2053" dir="ltr"/>
      </div>
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">API Token (اختیاری)</label>
        <input id="xui_token" type="text" placeholder="از Settings → Security پنل" dir="ltr"/>
      </div>
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">یوزرنیم ادمین</label>
        <input id="xui_user" type="text" dir="ltr"/>
      </div>
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">پسورد ادمین</label>
        <input id="xui_pass" type="password" dir="ltr"/>
      </div>
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">آدرس پایه سابسکریپشن (Sub URL)</label>
        <input id="xui_sub_url" type="url" placeholder="https://sub.example.com  (اگر جدا است)" dir="ltr"/>
        <p style="font-size:10px;color:#94a3b8;margin:3px 0 0">اگر خالی بگذارید، از Panel URL استفاده می‌شود</p>
      </div>
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">مسیر ساب (Sub Path)</label>
        <input id="xui_sub_path" type="text" value="/sub/" dir="ltr"/>
      </div>
    </div>
    <div style="margin-top:10px;display:flex;gap:8px;align-items:center">
      <button class="btn btn-gray" onclick="testXui()">تست اتصال X-UI</button>
      <span id="xui_test_res" style="font-size:12px"></span>
    </div>
  </div>

  <!-- Pasarguard -->
  <div style="background:#faf5ff;border:1px solid #e9d5ff;border-radius:10px;padding:16px;margin-bottom:16px">
    <h3 style="font-size:13px;font-weight:700;color:#7c3aed;margin-bottom:12px">🟣 پنل Pasarguard — مقصد</h3>
    <div class="field-group">
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">آدرس پنل</label>
        <input id="pg_url" type="url" placeholder="https://pg.example.com" dir="ltr"/>
      </div>
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">یوزرنیم ادمین</label>
        <input id="pg_user" type="text" dir="ltr"/>
      </div>
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">پسورد ادمین</label>
        <input id="pg_pass" type="password" dir="ltr"/>
      </div>
      <div>
        <label style="font-size:11px;color:#64748b;display:block;margin-bottom:4px">گروه پیش‌فرض (Group)</label>
        <div style="display:flex;gap:6px">
          <select id="pg_group" style="flex:1">
            <option value="">ابتدا گروه‌ها را بارگذاری کنید ↓</option>
          </select>
          <button class="btn btn-gray" style="white-space:nowrap" onclick="fetchPgGroups()">بارگذاری</button>
        </div>
      </div>
    </div>
    <div style="margin-top:10px;display:flex;gap:8px;align-items:center">
      <button class="btn btn-gray" onclick="testPg()">تست اتصال Pasarguard</button>
      <span id="pg_test_res" style="font-size:12px"></span>
    </div>
  </div>

  <button class="btn btn-primary" id="btn_load_users" onclick="goPreview()">
    بارگذاری کاربران X-UI &larr; مرحله بعد
  </button>
</div>

<!-- ══════════════ STEP 2: PREVIEW ══════════════ -->
<div id="step2" class="card hidden">
  <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">
    <h2 style="font-size:15px;font-weight:700;color:#1e293b;margin:0">👥 مرحله ۲: پیش‌نمایش کاربران</h2>
    <button class="btn btn-gray" style="font-size:12px;padding:5px 12px" onclick="showStep(1)">← بازگشت</button>
  </div>
  <p style="font-size:12px;color:#64748b;margin-bottom:12px">کاربران مورد نظر برای مهاجرت را انتخاب کنید</p>
  <div id="preview_stats" style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:14px"></div>
  <div style="overflow-x:auto">
    <table style="width:100%;border-collapse:collapse">
      <thead>
        <tr>
          <th><input type="checkbox" id="chk_all" onchange="toggleAll(this)"/></th>
          <th>نام کاربری</th>
          <th>Subscription ID</th>
          <th>حجم باقیمانده</th>
          <th>روز باقیمانده</th>
          <th>وضعیت</th>
          <th>لینک ساب فعلی</th>
        </tr>
      </thead>
      <tbody id="preview_tbody"></tbody>
    </table>
  </div>
  <div style="margin-top:14px;display:flex;gap:10px;align-items:center;flex-wrap:wrap">
    <button class="btn btn-primary" onclick="startMigration()">🚀 شروع مهاجرت انتخاب‌شده‌ها</button>
    <span id="sel_count" style="font-size:12px;color:#64748b"></span>
  </div>
</div>

<!-- ══════════════ STEP 3: MIGRATE ══════════════ -->
<div id="step3" class="card hidden">
  <h2 style="font-size:15px;font-weight:700;color:#1e293b;margin-bottom:14px">🔄 مرحله ۳: در حال مهاجرت</h2>
  <div style="display:flex;justify-content:space-between;font-size:12px;color:#64748b;margin-bottom:6px">
    <span id="mig_label">آماده‌سازی...</span>
    <span id="mig_pct">۰٪</span>
  </div>
  <div class="progress-bar" style="margin-bottom:16px">
    <div class="progress-fill" id="mig_bar" style="width:0%"></div>
  </div>
  <div style="display:flex;gap:20px;margin-bottom:14px;flex-wrap:wrap">
    <div style="background:#dcfce7;border-radius:8px;padding:8px 16px;text-align:center;min-width:80px">
      <div style="font-size:22px;font-weight:700;color:#16a34a" id="cnt_ok">0</div>
      <div style="font-size:11px;color:#166534">موفق</div>
    </div>
    <div style="background:#fee2e2;border-radius:8px;padding:8px 16px;text-align:center;min-width:80px">
      <div style="font-size:22px;font-weight:700;color:#dc2626" id="cnt_err">0</div>
      <div style="font-size:11px;color:#991b1b">خطا</div>
    </div>
    <div style="background:#f1f5f9;border-radius:8px;padding:8px 16px;text-align:center;min-width:80px">
      <div style="font-size:22px;font-weight:700;color:#475569" id="cnt_rem">0</div>
      <div style="font-size:11px;color:#64748b">در صف</div>
    </div>
  </div>
  <div class="log-box" id="mig_log"></div>
</div>

<!-- ══════════════ STEP 4: REPORT ══════════════ -->
<div id="step4" class="card hidden">
  <h2 style="font-size:15px;font-weight:700;color:#1e293b;margin-bottom:14px">📋 مرحله ۴: گزارش نهایی</h2>
  <div id="report_summary" style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:20px"></div>

  <!-- Redirect files section -->
  <div style="background:#faf5ff;border:1px solid #e9d5ff;border-radius:12px;padding:16px;margin-bottom:20px">
    <h3 style="font-size:13px;font-weight:700;color:#7c3aed;margin-bottom:8px">
      🔀 فایل‌های Redirect برای هاست اشتراکی
    </h3>
    <p style="font-size:12px;color:#475569;margin-bottom:12px">
      این دو فایل را روی هاست اشتراکی که <strong>Sub قدیمی X-UI</strong> روی آن بود آپلود کنید.
      هر درخواست <code>/sub/OLD_TOKEN</code> به آدرس جدید Pasarguard redirect می‌شود — کاربران هیچ تغییری احساس نخواهند کرد.
    </p>
    <div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px">
      <button class="btn btn-primary" onclick="downloadRedirectFiles()">
        ⬇️ دانلود فایل‌های Redirect
      </button>
      <span id="redirect_status" style="font-size:12px;align-self:center;color:#64748b"></span>
    </div>
    <div id="redirect_preview" class="hidden">
      <div style="margin-bottom:10px">
        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px">
          <span style="font-size:11px;font-weight:700;color:#475569">📄 xui_sub_forwarder.php</span>
          <button class="btn btn-gray" style="font-size:11px;padding:3px 10px" onclick="copyText('preview_php')">کپی</button>
        </div>
        <pre id="preview_php" style="background:#0f172a;color:#e2e8f0;padding:12px;border-radius:8px;font-size:11px;overflow-x:auto;direction:ltr;text-align:left;max-height:200px;overflow-y:auto"></pre>
      </div>
      <div>
        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px">
          <span style="font-size:11px;font-weight:700;color:#475569">📄 .htaccess</span>
          <button class="btn btn-gray" style="font-size:11px;padding:3px 10px" onclick="copyText('preview_htaccess')">کپی</button>
        </div>
        <pre id="preview_htaccess" style="background:#0f172a;color:#e2e8f0;padding:12px;border-radius:8px;font-size:11px;overflow-x:auto;direction:ltr;text-align:left"></pre>
      </div>
    </div>
  </div>

  <!-- Results table -->
  <h3 style="font-size:13px;font-weight:700;color:#1e293b;margin-bottom:8px">جزئیات مهاجرت:</h3>
  <div style="overflow-x:auto">
    <table style="width:100%;border-collapse:collapse">
      <thead>
        <tr>
          <th>کاربر X-UI</th>
          <th>نام در Pasarguard</th>
          <th>نتیجه</th>
          <th>ساب X-UI (قدیم)</th>
          <th>ساب Pasarguard (جدید)</th>
        </tr>
      </thead>
      <tbody id="report_tbody"></tbody>
    </table>
  </div>
  <div style="margin-top:16px;display:flex;gap:8px">
    <button class="btn btn-gray" onclick="location.reload()">🔄 شروع مجدد</button>
  </div>
</div>

</div><!-- /container -->

<script>
var allUsers = [];
var selUsers = [];
var results  = [];

// ─── util ────────────────────────────────────────────────────────────────────
function apiPost(url, formData, cb) {
    fetch(url, { method: 'POST', body: formData })
        .then(function(r) {
            var ct = r.headers.get('content-type') || '';
            if (!ct.includes('application/json')) {
                return r.text().then(function(txt) {
                    cb({ ok: false, msg: 'پاسخ غیر JSON از سرور: ' + txt.substring(0, 200) });
                });
            }
            return r.json().then(cb);
        })
        .catch(function(e) { cb({ ok: false, msg: 'خطای شبکه: ' + e }); });
}
function mkFd(obj) {
    var fd = new FormData();
    for (var k in obj) {
        var v = obj[k];
        fd.append(k, (v !== null && typeof v === 'object') ? JSON.stringify(v) : String(v));
    }
    return fd;
}
function esc(s) {
    return String(s ?? '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
function showStep(n) {
    [1,2,3,4].forEach(function(i) {
        document.getElementById('step'+i).classList.toggle('hidden', i !== n);
        var d = document.getElementById('dot'+i);
        d.className = 'step-dot ' + (i < n ? 'step-done' : i === n ? 'step-active' : 'step-pending');
    });
}
function statCard(label, val, bg) {
    return '<div style="background:' + bg + ';border-radius:8px;padding:10px 16px;min-width:100px;text-align:center">'
        + '<div style="font-size:24px;font-weight:700">' + val + '</div>'
        + '<div style="font-size:11px;opacity:.8;margin-top:2px">' + label + '</div></div>';
}
function logLine(cls, msg) {
    var box = document.getElementById('mig_log');
    var d = document.createElement('div');
    d.className = 'log-' + cls;
    d.textContent = new Date().toLocaleTimeString('fa-IR') + ' › ' + msg;
    box.appendChild(d);
    box.scrollTop = box.scrollHeight;
}

// ─── getters ─────────────────────────────────────────────────────────────────
function getXui() {
    return {
        url:      document.getElementById('xui_url').value.trim(),
        user:     document.getElementById('xui_user').value.trim(),
        pass:     document.getElementById('xui_pass').value.trim(),
        token:    document.getElementById('xui_token').value.trim(),
        sub_url:  document.getElementById('xui_sub_url').value.trim(),
        sub_path: document.getElementById('xui_sub_path').value.trim() || '/sub/',
    };
}
function getPg() {
    return {
        url:      document.getElementById('pg_url').value.trim(),
        user:     document.getElementById('pg_user').value.trim(),
        pass:     document.getElementById('pg_pass').value.trim(),
        group_id: document.getElementById('pg_group').value,
    };
}

// ─── connection tests ─────────────────────────────────────────────────────────
function testXui() {
    var el = document.getElementById('xui_test_res');
    el.textContent = '⏳ در حال تست...';
    var x = getXui();
    apiPost('?action=test_xui', mkFd({url:x.url,user:x.user,pass:x.pass,token:x.token}), function(r) {
        el.textContent = r.msg;
        el.style.color = r.ok ? '#16a34a' : '#dc2626';
    });
}
function testPg() {
    var el = document.getElementById('pg_test_res');
    el.textContent = '⏳ در حال تست...';
    var p = getPg();
    apiPost('?action=test_pg', mkFd({pg_url:p.url,pg_user:p.user,pg_pass:p.pass}), function(r) {
        el.textContent = r.msg;
        el.style.color = r.ok ? '#16a34a' : '#dc2626';
    });
}
function fetchPgGroups() {
    var p = getPg();
    if (!p.url || !p.user) { alert('آدرس و یوزرنیم Pasarguard را وارد کنید'); return; }
    var el = document.getElementById('pg_test_res');
    el.textContent = '⏳ در حال بارگذاری گروه‌ها...';
    apiPost('?action=fetch_pg_groups', mkFd({pg_url:p.url,pg_user:p.user,pg_pass:p.pass}), function(r) {
        var sel = document.getElementById('pg_group');
        sel.innerHTML = '';
        if (!r.ok || !r.groups || !r.groups.length) {
            sel.innerHTML = '<option value="">گروهی یافت نشد</option>';
            el.textContent = '❌ ' + (r.msg || 'گروه یافت نشد');
            el.style.color = '#dc2626';
            return;
        }
        sel.innerHTML = '<option value="">— انتخاب گروه —</option>';
        r.groups.forEach(function(g) {
            var o = document.createElement('option');
            o.value = g.id; o.textContent = g.name;
            sel.appendChild(o);
        });
        el.textContent = '✅ ' + r.groups.length + ' گروه بارگذاری شد';
        el.style.color = '#16a34a';
    });
}

// ─── step 1 → 2 ──────────────────────────────────────────────────────────────
function goPreview() {
    var x = getXui(), p = getPg();
    if (!x.url)      { alert('آدرس پنل X-UI را وارد کنید'); return; }
    if (!p.url)      { alert('آدرس پنل Pasarguard را وارد کنید'); return; }
    if (!p.group_id) { alert('یک گروه Pasarguard انتخاب کنید'); return; }

    var btn = document.getElementById('btn_load_users');
    btn.disabled = true; btn.textContent = '⏳ در حال بارگذاری...';

    var fd = new FormData();
    Object.keys(x).forEach(function(k) { fd.append('xui[' + k + ']', x[k]); });
    Object.keys(p).forEach(function(k) { fd.append('pg['  + k + ']', p[k]); });

    fetch('?action=load_users', { method: 'POST', body: fd })
        .then(function(resp) {
            var ct = resp.headers.get('content-type') || '';
            if (!ct.includes('json')) {
                return resp.text().then(function(txt) {
                    btn.disabled = false; btn.textContent = 'بارگذاری کاربران X-UI ← مرحله بعد';
                    alert('❌ پاسخ غیر JSON:\n' + txt.substring(0, 400));
                });
            }
            return resp.json().then(function(r) {
                btn.disabled = false; btn.textContent = 'بارگذاری کاربران X-UI ← مرحله بعد';
                if (!r.ok) { alert('❌ ' + r.msg); return; }
                allUsers = r.users;
                renderPreview(r.users);
                showStep(2);
            });
        })
        .catch(function(e) {
            btn.disabled = false; btn.textContent = 'بارگذاری کاربران X-UI ← مرحله بعد';
            alert('❌ خطای شبکه: ' + e);
        });
}

// ─── preview ─────────────────────────────────────────────────────────────────
function renderPreview(users) {
    var active = users.filter(u => u.enable).length;
    var noSub  = users.filter(u => !u.subId).length;
    document.getElementById('preview_stats').innerHTML =
        statCard('کل کاربران', users.length, '#ede9fe') +
        statCard('فعال', active, '#dcfce7') +
        statCard('غیرفعال', users.length - active, '#fee2e2') +
        (noSub > 0 ? statCard('بدون subId', noSub, '#fef3c7') : '');

    var tbody = document.getElementById('preview_tbody');
    tbody.innerHTML = '';
    users.forEach(function(u) {
        var tr = document.createElement('tr');
        var subTrunc = u.xuiSub ? (u.xuiSub.length > 55 ? u.xuiSub.substring(0, 55) + '…' : u.xuiSub) : '—';
        tr.innerHTML =
            '<td><input type="checkbox" class="user-chk" data-email="' + esc(u.email) + '" ' + (u.enable ? 'checked' : '') + '/></td>' +
            '<td style="font-family:monospace;font-size:11px">' + esc(u.email) + '</td>' +
            '<td style="font-family:monospace;font-size:10px;direction:ltr;color:#7c3aed">' + (u.subId ? esc(u.subId) : '<span style="color:#dc2626">—</span>') + '</td>' +
            '<td>' + (u.remGB > 0 ? u.remGB + ' GB' : '<span style="color:#7c3aed">نامحدود</span>') + '</td>' +
            '<td>' + (u.remDays > 0 ? u.remDays + ' روز' : '<span style="color:#7c3aed">بدون انقضا</span>') + '</td>' +
            '<td>' + (u.enable ? '<span class="badge-ok">فعال</span>' : '<span class="badge-warn">غیرفعال</span>') + '</td>' +
            '<td style="font-size:10px;direction:ltr;color:#6366f1;max-width:200px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis" title="' + esc(u.xuiSub) + '">' + esc(subTrunc) + '</td>';
        tbody.appendChild(tr);
    });
    updateSelCount();
    document.querySelectorAll('.user-chk').forEach(function(c) {
        c.addEventListener('change', updateSelCount);
    });
}
function toggleAll(m) {
    document.querySelectorAll('.user-chk').forEach(function(c) { c.checked = m.checked; });
    updateSelCount();
}
function updateSelCount() {
    var n = document.querySelectorAll('.user-chk:checked').length;
    document.getElementById('sel_count').textContent = n + ' کاربر انتخاب شده';
}

// ─── migration ────────────────────────────────────────────────────────────────
function startMigration() {
    selUsers = [];
    document.querySelectorAll('.user-chk:checked').forEach(function(c) {
        selUsers.push(c.dataset.email);
    });
    if (!selUsers.length) { alert('حداقل یک کاربر انتخاب کنید'); return; }
    results = [];
    document.getElementById('mig_log').innerHTML = '';
    document.getElementById('cnt_ok').textContent  = '0';
    document.getElementById('cnt_err').textContent = '0';
    document.getElementById('cnt_rem').textContent = selUsers.length;
    showStep(3);
    logLine('info', 'شروع مهاجرت ' + selUsers.length + ' کاربر — subId یکسان ارسال می‌شود');
    migrateNext(0);
}
function migrateNext(idx) {
    if (idx >= selUsers.length) { showReport(); return; }
    var email = selUsers[idx];
    var total = selUsers.length;
    var pct   = Math.round((idx / total) * 100);
    document.getElementById('mig_bar').style.width  = pct + '%';
    document.getElementById('mig_pct').textContent  = pct + '٪';
    document.getElementById('mig_label').textContent = 'در حال مهاجرت: ' + email + ' (' + (idx+1) + '/' + total + ')';
    document.getElementById('cnt_rem').textContent  = total - idx;

    var fd = new FormData(); fd.append('email', email);
    fetch('?action=migrate_one', { method: 'POST', body: fd })
        .then(function(resp) {
            var ct = resp.headers.get('content-type') || '';
            if (!ct.includes('json')) {
                return resp.text().then(function(txt) {
                    var r = { ok: false, email: email, msg: 'پاسخ غیر JSON: ' + txt.substring(0, 150) };
                    results.push(r);
                    document.getElementById('cnt_err').textContent = parseInt(document.getElementById('cnt_err').textContent) + 1;
                    logLine('err', '❌ ' + email + ': ' + r.msg);
                    setTimeout(function() { migrateNext(idx + 1); }, 250);
                });
            }
            return resp.json().then(function(r) {
                results.push(r);
                var cntEl = r.ok ? 'cnt_ok' : 'cnt_err';
                document.getElementById(cntEl).textContent = parseInt(document.getElementById(cntEl).textContent) + 1;
                if (r.ok) {
                    var noteStr = r.note ? ' — ' + r.note : '';
                    logLine('ok', '✅ ' + email + (r.pgUsername && r.pgUsername !== email ? ' → ' + r.pgUsername : '') + noteStr);
                } else {
                    logLine('err', '❌ ' + email + ': ' + (r.msg || 'خطا'));
                }
                setTimeout(function() { migrateNext(idx + 1); }, 250);
            });
        })
        .catch(function(e) {
            results.push({ ok: false, email: email, msg: String(e) });
            document.getElementById('cnt_err').textContent = parseInt(document.getElementById('cnt_err').textContent) + 1;
            logLine('err', '❌ ' + email + ': ' + e);
            setTimeout(function() { migrateNext(idx + 1); }, 250);
        });
}

// ─── report ───────────────────────────────────────────────────────────────────
function showReport() {
    document.getElementById('mig_bar').style.width = '100%';
    document.getElementById('mig_pct').textContent = '۱۰۰٪';
    document.getElementById('mig_label').textContent = '✅ مهاجرت کامل شد!';
    logLine('ok', '══════════ پایان مهاجرت ══════════');

    var ok  = results.filter(function(r) { return r.ok; }).length;
    var err = results.filter(function(r) { return !r.ok; }).length;

    showStep(4);
    document.getElementById('report_summary').innerHTML =
        statCard('موفق',   ok,  '#dcfce7') +
        statCard('ناموفق', err, '#fee2e2') +
        statCard('کل',     results.length, '#ede9fe');

    var tbody = document.getElementById('report_tbody');
    tbody.innerHTML = '';
    results.forEach(function(r) {
        var tr = document.createElement('tr');
        var pgName = r.pgUsername && r.pgUsername !== r.email
            ? '<span style="color:#dc2626">' + esc(r.pgUsername) + '</span><br/><span style="font-size:10px;color:#94a3b8">تغییر یافت</span>'
            : (r.ok ? esc(r.email) : '—');
        tr.innerHTML =
            '<td style="font-family:monospace;font-size:11px">' + esc(r.email) + '</td>' +
            '<td style="font-family:monospace;font-size:11px">' + pgName + '</td>' +
            '<td>' + (r.ok ? '<span class="badge-ok">موفق</span>' : '<span class="badge-err">' + esc(r.msg || 'خطا') + '</span>') + '</td>' +
            '<td style="font-size:10px;direction:ltr;word-break:break-all;max-width:180px">' + esc(r.xuiSub || '—') + '</td>' +
            '<td style="font-size:10px;direction:ltr;word-break:break-all;max-width:180px">' + esc(r.pgSub  || '—') + '</td>';
        tbody.appendChild(tr);
    });
}

function downloadRedirectFiles() {
    var el = document.getElementById('redirect_status');
    el.textContent = '⏳ در حال ساخت فایل‌ها...';
    fetch('?action=get_redirect_files')
        .then(function(resp) { return resp.json(); })
        .then(function(r) {
            if (!r.ok) { el.textContent = '❌ ' + r.msg; return; }
            el.textContent = '✅ ' + r.count + ' مسیر در فایل‌ها';
            document.getElementById('preview_php').textContent     = r.php;
            document.getElementById('preview_htaccess').textContent = r.htaccess;
            document.getElementById('redirect_preview').classList.remove('hidden');
            // Auto-download both files
            dlFile('xui_sub_forwarder.php', r.php);
            setTimeout(function() { dlFile('.htaccess', r.htaccess); }, 400);
        })
        .catch(function(e) { el.textContent = '❌ خطا: ' + e; });
}

function dlFile(name, content) {
    var a = document.createElement('a');
    a.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(content);
    a.download = name;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
}

function copyText(id) {
    var el = document.getElementById(id);
    navigator.clipboard.writeText(el.textContent).then(function() {
        alert('کپی شد ✓');
    }).catch(function() {
        el.select(); document.execCommand('copy');
    });
}

// ─── init ─────────────────────────────────────────────────────────────────────
showStep(1);
</script>
</body>
</html>
