const ADMIN_KEY = "weavy_admin_password";
const POOL_LIST_HIDDEN_KEY = "weavy_pool_list_hidden";
const CAPTCHA_ALARM_ENABLED_KEY = "weavy_captcha_alarm_enabled";
const CAPTCHA_ALARM_SOUND_DATA_KEY = "weavy_captcha_alarm_sound_data";
const CAPTCHA_ALARM_SOUND_NAME_KEY = "weavy_captcha_alarm_sound_name";
let adminPass = "";
let sseSource = null;
let creatorCountdownInterval = null;
let creatorNextRunTime = null;
let reviveCountdownInterval = null;
let reviveNextRunTime = null;
let statusRefreshInterval = null;
let poolListHidden = sessionStorage.getItem(POOL_LIST_HIDDEN_KEY) === "true";
let lastCaptchaAlarmAt = 0;
let captchaAlarmLoop = null;
let captchaAlarmActive = false;
let captchaAlarmEnabled = localStorage.getItem(CAPTCHA_ALARM_ENABLED_KEY) !== "false";
let captchaAlarmSoundData = localStorage.getItem(CAPTCHA_ALARM_SOUND_DATA_KEY) || "";
let captchaAlarmSoundName = localStorage.getItem(CAPTCHA_ALARM_SOUND_NAME_KEY) || "";
let currentAccounts = [];
let audioUnlocked = false;
let globalAudioCtx = null;

const $ = (id) => document.getElementById(id);
const els = {
  loginScreen: $("login-screen"),
  adminScreen: $("admin-screen"),
  password: $("admin-password"),
  loginBtn: $("login-btn"),
  loginStatus: $("login-status"),

  cleanBtn: $("clean-btn"),
  syncBtn: $("sync-btn"),
  refreshBtn: $("refresh-btn"),
  logoutBtn: $("logout-btn"),
  poolCollapseBtn: $("pool-collapse-btn"),
  poolSettingsSaveBtn: $("pool-save-settings-btn"),
  poolResetMonthlyBtn: $("pool-reset-monthly-btn"),
  poolMaxRunsInput: $("pool-max-runs"),
  poolMonthlyCreditsInput: $("pool-monthly-credits"),
  poolSettingsMsg: $("pool-settings-msg"),
  stats: $("stats"),
  accountList: $("account-list"),
  archiveList: $("archive-list"),
  archiveCount: $("archive-count"),
  archiveTabCount: $("archive-tab-count"),
  tabBtnPool: $("tab-btn-pool"),
  tabBtnArchive: $("tab-btn-archive"),
  tabBtnVoucher: $("tab-btn-voucher"),
  tabBtnTools: $("tab-btn-tools"),
  tabBtnIcloud: $("tab-btn-icloud"),
  tabBtnOwner: $("tab-btn-owner"),
  tabPanelPool: $("tab-panel-pool"),
  tabPanelArchive: $("tab-panel-archive"),
  tabPanelVoucher: $("tab-panel-voucher"),
  tabPanelTools: $("tab-panel-tools"),
  tabPanelIcloud: $("tab-panel-icloud"),
  tabPanelOwner: $("tab-panel-owner"),
  deleteAllArchiveBtn: $("delete-all-archive-btn"),
  poolSize: $("pool-size"),

  addToken: $("add-token"),
  addRecipe: $("add-recipe"),
  addLabel: $("add-label"),
  addBtn: $("add-btn"),

  bulkText: $("bulk-text"),
  bulkBtn: $("bulk-btn"),

  editForm: $("edit-form"),
  addManualCard: $("add-manual-card"),
  bulkImportCard: $("bulk-import-card"),
  editId: $("edit-id"),
  editToken: $("edit-token"),
  editRecipe: $("edit-recipe"),
  editLabel: $("edit-label"),
  saveEditBtn: $("save-edit-btn"),
  cancelEditBtn: $("cancel-edit-btn"),

  // Bot elements
  botRunBtn: $("bot-run-btn"),
  botReviveRunBtn: $("bot-revive-run-btn"),
  botStopBtn: $("bot-stop-btn"),
  botStatusBadge: $("bot-status-badge"),
  creatorCountdown: $("creator-bot-countdown"),
  creatorCountdownTimer: $("creator-countdown-timer"),
  creatorSchedulerToggle: $("creator-scheduler-toggle"),
  creatorSchedulerInterval: $("creator-scheduler-interval"),
  creatorSchedulerIntervalCustom: $("creator-scheduler-interval-custom"),
  creatorSchedulerSaveBtn: $("creator-scheduler-save-btn"),
  reviveCountdown: $("revive-bot-countdown"),
  reviveCountdownTimer: $("revive-countdown-timer"),
  reviveSchedulerToggle: $("revive-scheduler-toggle"),
  reviveSchedulerInterval: $("revive-scheduler-interval"),
  reviveSchedulerIntervalCustom: $("revive-scheduler-interval-custom"),
  reviveSchedulerSaveBtn: $("revive-scheduler-save-btn"),
  schedulerTestSeconds: $("scheduler-test-seconds"),
  schedulerTestBtn: $("scheduler-test-btn"),
  logBody: $("log-body"),
  logClearBtn: $("log-clear-btn"),
  botLastRun: $("bot-last-run"),
  botLastRunText: $("bot-last-run-text"),
  headlessToggle: $("headless-toggle"),

  // Bulk bot elements
  bulkEmailInput: $("bulk-email-input"),
  botBulkRunBtn: $("bot-bulk-run-btn"),
  botBulkStopBtn: $("bot-bulk-stop-btn"),
  bulkBotStatus: $("bulk-bot-status"),

  // Generate Email elements
  genEmailPrefix: $("gen-email-prefix"),
  genEmailCount: $("gen-email-count"),
  genEmailBtn: $("gen-email-btn"),
  genEmailRefreshBtn: $("gen-email-refresh-btn"),
  genEmailResult: $("gen-email-result"),
  genEmailList: $("gen-email-list"),
  genEmailUseAllBtn: $("gen-email-use-all-btn"),
  genEmailCountLabel: $("gen-email-count-label"),

  // Inbox viewer elements
  inboxRefreshBtn: $("inbox-refresh-btn"),
  inboxList: $("inbox-list"),
  inboxDetail: $("inbox-detail"),

  // ICLOUD Settings elements
  icloudStatusBadge: $("icloud-status-badge"),
  icloudTestBtn: $("icloud-test-btn"),
  icloudAccountId: $("icloud-account-id"),
  icloudAccName: $("icloud-acc-name"),
  icloudAccDsid: $("icloud-acc-dsid"),
  icloudAccClientId: $("icloud-acc-clientid"),
  icloudAccCookies: $("icloud-acc-cookies"),
  icloudAccEmail: $("icloud-acc-email"),
  icloudAccAppPassword: $("icloud-acc-apppassword"),
  icloudAccSubdomain: $("icloud-acc-subdomain"),
  icloudAccountList: $("icloud-account-list"),
  icloudAccountSaveBtn: $("icloud-account-save-btn"),
  icloudAccountDeleteBtn: $("icloud-account-delete-btn"),
  icloudAccountNewBtn: $("icloud-account-new-btn"),
  icloudAccountClearBtn: $("icloud-account-clear-btn"),
  icloudJsonToggleBtn: $("icloud-json-toggle-btn"),
  icloudFormMode: $("icloud-form-mode"),
  icloudJsonMode: $("icloud-json-mode"),
  icloudAccJson: $("icloud-acc-json"),
  icloudSettingsMsg: $("icloud-settings-msg"),

  captchaAlarmToggle: $("captcha-alarm-toggle"),
  captchaAlarmSoundFile: $("captcha-alarm-sound-file"),
  captchaAlarmTestBtn: $("captcha-alarm-test-btn"),
  captchaAlarmResetBtn: $("captcha-alarm-reset-btn"),
  captchaAlarmStatus: $("captcha-alarm-status"),

  // Voucher elements
  vchCode: $("vch-code"),
  vchTier: $("vch-tier"),
  createVchBtn: $("create-vch-btn"),
  voucherList: $("voucher-list"),
  vchWhatsapp: $("vch-whatsapp"),
  vchDuration: $("vch-duration"),
  vchDurationDays: $("vch-duration-days"),
  vchDurationDaysWrapper: $("vch-duration-days-wrapper"),
  vchDailyLimit: $("vch-daily-limit"),
  vchPricePaid: $("vch-price-paid"),
  expiringModal: $("expiring-modal"),
  expiringList: $("expiring-list"),
  expiringThreshold: $("expiring-threshold-select"),
  expiringRefreshBtn: $("expiring-refresh-btn"),
  expiringCloseBtn: $("expiring-close-btn"),
  expiringSnoozeBtn: $("expiring-snooze-btn"),
  selectAllChk: $("select-all-chk"),
  archiveSelectedBtn: $("archive-selected-btn"),
  deleteSelectedBtn: $("delete-selected-btn"),
  editVchForm: $("edit-voucher-form"),
  editVchOriginalCode: $("edit-vch-original-code"),
  editVchCode: $("edit-vch-code"),
  editVchWhatsapp: $("edit-vch-whatsapp"),
  editVchTier: $("edit-vch-tier"),
  editVchDailyLimit: $("edit-vch-daily-limit"),
  editVchExpiresAt: $("edit-vch-expires-at"),

  saveEditVchBtn: $("save-edit-vch-btn"),
  cancelEditVchBtn: $("cancel-edit-vch-btn"),

  // Owner settings elements
  ownerKasirPassword: $("owner-kasir-password"),
  ownerPricePro: $("owner-price-pro"),
  ownerPriceReseller: $("owner-price-reseller"),
  ownerPriceVip: $("owner-price-vip"),
  ownerPriceResellerVip: $("owner-price-reseller-vip"),
  ownerSaveSettingsBtn: $("owner-save-settings-btn"),
  resellerName: $("reseller-name"),
  resellerPassword: $("reseller-password"),
  resellerQuota: $("reseller-quota"),
  resellerAllowBot: $("reseller-allow-bot"),
  resellerAllowPool: $("reseller-allow-pool"),
  resellerAllowArchive: $("reseller-allow-archive"),
  resellerDebtEnabled: $("reseller-debt-enabled"),
  resellerDebtLimit: $("reseller-debt-limit"),
  createResellerBtn: $("create-reseller-btn"),
  resellerList: $("reseller-list"),
  editResellerForm: $("edit-reseller-form"),
  editResellerId: $("edit-reseller-id"),
  editResellerName: $("edit-reseller-name"),
  editResellerPassword: $("edit-reseller-password"),
  editResellerQuota: $("edit-reseller-quota"),
  editResellerAllowBot: $("edit-reseller-allow-bot"),
  editResellerAllowPool: $("edit-reseller-allow-pool"),
  editResellerAllowArchive: $("edit-reseller-allow-archive"),
  editResellerDebtEnabled: $("edit-reseller-debt-enabled"),
  editResellerDebtLimit: $("edit-reseller-debt-limit"),
  saveEditResellerBtn: $("save-edit-reseller-btn"),
  cancelEditResellerBtn: $("cancel-edit-reseller-btn"),
  resellerInfoBar: $("reseller-info-bar"),
  infoResellerName: $("info-reseller-name"),
  infoResellerQuota: $("info-reseller-quota"),
  resellerBalance: $("reseller-balance"),
  resellerCustomPrice: $("reseller-custom-price"),
  resellerCustomSrp: $("reseller-custom-srp"),
  resellerCustomPriceVip: $("reseller-custom-price-vip"),
  resellerCustomSrpVip: $("reseller-custom-srp-vip"),
  editResellerBalance: $("edit-reseller-balance"),
  editResellerCustomPrice: $("edit-reseller-custom-price"),
  editResellerCustomSrp: $("edit-reseller-custom-srp"),
  editResellerCustomPriceVip: $("edit-reseller-custom-price-vip"),
  editResellerCustomSrpVip: $("edit-reseller-custom-srp-vip"),
  infoResellerBalance: $("info-reseller-balance"),
  infoResellerCommission: $("info-reseller-commission"),
  mitraCustomSrp: $("mitra-custom-srp"),
  mitraCustomSrpVip: $("mitra-custom-srp-vip"),
  saveMitraSrpBtn: $("save-mitra-srp-btn"),
  btnToggleMaintenanceModal: $("btn-toggle-maintenance-modal"),
  maintenanceModal: $("maintenance-modal"),
  mActive: $("m-active"),
  mTitle: $("m-title"),
  mDescription: $("m-description"),
  mReason: $("m-reason"),
  mDurationSelect: $("m-duration-select"),
  mDurationCustomWrapper: $("m-duration-custom-wrapper"),
  mDurationCustom: $("m-duration-custom"),
  mSaveBtn: $("m-save-btn"),
  mCancelBtn: $("m-cancel-btn"),
  adminMaintenanceStatusText: $("admin-maintenance-status-text"),
  adminMaintenanceDetailText: $("admin-maintenance-detail-text"),
  // Finance tab elements
  tabBtnFinance: $("tab-btn-finance"),
  tabPanelFinance: $("tab-panel-finance"),
  finTodayIncome: $("fin-today-income"),
  finTodayTxn: $("fin-today-txn"),
  finWeekIncome: $("fin-week-income"),
  finWeekTxn: $("fin-week-txn"),
  finMonthIncome: $("fin-month-income"),
  finMonthTxn: $("fin-month-txn"),
  finTotalIncome: $("fin-total-income"),
  finBalance: $("fin-balance"),
  finResellerCards: $("fin-reseller-cards"),
  finLastUpdated: $("finance-last-updated"),
  finFilterDate: $("fin-filter-date"),
  finFilterType: $("fin-filter-type"),
  finFilterActor: $("fin-filter-actor"),
  finFilterSearch: $("fin-filter-search"),
  finRefreshBtn: $("fin-refresh-btn"),
  finReportSummary: $("finance-report-summary"),
  finTxnBody: $("finance-txn-body"),
  finPagination: $("finance-pagination"),
  finTopupReseller: $("fin-topup-reseller"),
  finTopupAmount: $("fin-topup-amount"),
  finTopupNote: $("fin-topup-note"),
  finTopupBtn: $("fin-topup-btn"),
  finTopupFeedback: $("fin-topup-feedback"),
  // Trial voucher elements
  trialAutoBtn: $("trial-auto-btn"),
  trialCustomBtn: $("trial-custom-btn"),
  trialQuotaRemaining: $("trial-quota-remaining"),
  trialResultMsg: $("trial-result-msg"),
  // Full-access management elements
  fullAccessMitraControls: $("full-access-mitra-controls"),
  fullAccessStatusBadge: $("full-access-status-badge"),
  fullAccessRequestBtn: $("full-access-request-btn"),
  fullAccessPendingText: $("full-access-pending-text"),
  fullAccessPendingRequests: $("full-access-pending-requests"),
  fullAccessPendingList: $("full-access-pending-list"),
  fullAccessActiveListSection: $("full-access-active-list-section"),
  fullAccessActiveList: $("full-access-active-list"),
  fullAccessLogRefreshBtn: $("full-access-log-refresh-btn"),
  fullAccessLogFilter: $("full-access-log-filter"),
  fullAccessLogSearch: $("full-access-log-search"),
  fullAccessLogList: $("full-access-log-list"),
};

// ─── Utilities ──────────────────────────────────────────────────────────────

function setLoginStatus(text, type = "") {
  if (!text) { els.loginStatus.hidden = true; return; }
  els.loginStatus.hidden = false;
  els.loginStatus.textContent = text;
  els.loginStatus.className = `status ${type}`;
}

function showConfirm(message) {
  return new Promise((resolve) => {
    const modal = document.getElementById("custom-confirm-modal");
    const msgEl = document.getElementById("confirm-modal-msg");
    const confirmBtn = document.getElementById("confirm-modal-confirm");
    const cancelBtn = document.getElementById("confirm-modal-cancel");

    msgEl.textContent = message;
    modal.classList.add("active");

    const onConfirm = () => {
      cleanup();
      resolve(true);
    };

    const onCancel = () => {
      cleanup();
      resolve(false);
    };

    const cleanup = () => {
      modal.classList.remove("active");
      confirmBtn.removeEventListener("click", onConfirm);
      cancelBtn.removeEventListener("click", onCancel);
    };

    confirmBtn.addEventListener("click", onConfirm);
    cancelBtn.addEventListener("click", onCancel);
  });
}

function showPasswordPrompt() {
  return new Promise((resolve) => {
    const modal = document.getElementById("password-confirm-modal");
    const input = document.getElementById("pwconfirm-input");
    const error = document.getElementById("pwconfirm-error");
    const confirmBtn = document.getElementById("pwconfirm-confirm");
    const cancelBtn = document.getElementById("pwconfirm-cancel");

    input.value = "";
    error.style.display = "none";
    modal.classList.add("active");
    setTimeout(() => input.focus(), 100);

    const onConfirm = () => {
      const val = input.value.trim();
      if (!val) {
        error.textContent = "Password tidak boleh kosong!";
        error.style.display = "";
        input.focus();
        return;
      }
      cleanup();
      resolve(val);
    };

    const onCancel = () => {
      cleanup();
      resolve(null);
    };

    const onKeydown = (e) => {
      if (e.key === "Enter") onConfirm();
      if (e.key === "Escape") onCancel();
    };

    const cleanup = () => {
      modal.classList.remove("active");
      confirmBtn.removeEventListener("click", onConfirm);
      cancelBtn.removeEventListener("click", onCancel);
      input.removeEventListener("keydown", onKeydown);
    };

    confirmBtn.addEventListener("click", onConfirm);
    cancelBtn.addEventListener("click", onCancel);
    input.addEventListener("keydown", onKeydown);
  });
}

function showToast(message, type = "success", duration = 4000) {
  const container = document.getElementById("toast-container");
  if (!container) return;

  const toast = document.createElement("div");
  toast.className = `toast toast-${type}`;
  
  const icon = type === "success" ? "✅" : type === "warn" ? "⚠️" : "❌";
  toast.innerHTML = `<span>${icon}</span> <span>${message}</span>`;
  
  container.appendChild(toast);
  
  // Trigger animation
  setTimeout(() => {
    toast.classList.add("show");
  }, 50);

  // Auto remove
  setTimeout(() => {
    toast.classList.remove("show");
    setTimeout(() => {
      toast.remove();
    }, 300);
  }, duration);
}

function buildAuthHeaders() {
  return { "Content-Type": "application/json", "x-admin-password": adminPass };
}

async function api(path, opts = {}) {
  const headers = { "Content-Type": "application/json", "x-admin-password": adminPass, ...(opts.headers || {}) };
  const res = await fetch(path, { ...opts, headers });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
  return data;
}

function escapeHtml(s) {
  return String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c]));
}

function formatTimeLeft(exp) {
  if (!exp) return "no exp";
  const sec = exp - Date.now() / 1000;
  if (sec <= 0) return "expired";
  if (sec < 60) return `${Math.floor(sec)}s left`;
  if (sec < 3600) return `${Math.floor(sec / 60)}m left`;
  return `${Math.floor(sec / 3600)}h ${Math.floor((sec % 3600) / 60)}m left`;
}

function formatCountdown(diffMs) {
  const totalSeconds = Math.max(0, Math.floor(diffMs / 1000));
  const hours = Math.floor(totalSeconds / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  const seconds = totalSeconds % 60;
  if (hours > 0) {
    return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
  }
  return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
}

function unlockAudio() {
  if (audioUnlocked) return;
  try {
    const AudioCtx = window.AudioContext || window.webkitAudioContext;
    if (AudioCtx) {
      globalAudioCtx = new AudioCtx();
      if (globalAudioCtx.state === "suspended") {
        globalAudioCtx.resume().then(() => {
          audioUnlocked = true;
          updateCaptchaAlarmStatus();
          console.log("AudioContext unlocked successfully");
        }).catch(() => {});
      } else {
        audioUnlocked = true;
        updateCaptchaAlarmStatus();
      }
    }
  } catch (e) {
    console.error("Error unlocking audio:", e);
  }

  // Also try HTML5 Audio
  try {
    const dummy = new Audio();
    dummy.src = "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAAA";
    dummy.play().then(() => {
      audioUnlocked = true;
      updateCaptchaAlarmStatus();
    }).catch(() => {});
  } catch (e) {}

  if (audioUnlocked) {
    window.removeEventListener("click", unlockAudio);
    window.removeEventListener("keydown", unlockAudio);
    window.removeEventListener("mousedown", unlockAudio);
    window.removeEventListener("touchstart", unlockAudio);
  }
}

window.addEventListener("click", unlockAudio);
window.addEventListener("keydown", unlockAudio);
window.addEventListener("mousedown", unlockAudio);
window.addEventListener("touchstart", unlockAudio);

function playDefaultCaptchaAlarmTone() {
  try {
    const AudioCtx = window.AudioContext || window.webkitAudioContext;
    if (!AudioCtx) return;
    const ctx = globalAudioCtx || new AudioCtx();
    if (ctx.state === "suspended") {
      ctx.resume().catch(() => {});
    }
    const beep = (startAt, duration, freq) => {
      const osc = ctx.createOscillator();
      const gain = ctx.createGain();
      osc.type = "square";
      osc.frequency.value = freq;
      gain.gain.setValueAtTime(0.0001, startAt);
      gain.gain.exponentialRampToValueAtTime(0.5, startAt + 0.02);
      gain.gain.exponentialRampToValueAtTime(0.0001, startAt + duration);
      osc.connect(gain);
      gain.connect(ctx.destination);
      osc.start(startAt);
      osc.stop(startAt + duration + 0.03);
    };

    const base = ctx.currentTime + 0.02;
    beep(base, 0.22, 880);
    beep(base + 0.3, 0.22, 880);
    beep(base + 0.6, 0.4, 1175);
    if (ctx !== globalAudioCtx) {
      setTimeout(() => ctx.close().catch(() => {}), 1500);
    }
  } catch {}
}

function updateCaptchaAlarmStatus(message) {
  if (!els.captchaAlarmStatus) return;
  if (message) {
    els.captchaAlarmStatus.textContent = message;
    return;
  }
  const soundLabel = captchaAlarmSoundName ? `Custom: ${captchaAlarmSoundName}` : "Default beep";
  let statusText = `Alarm ${captchaAlarmEnabled ? "aktif" : "nonaktif"} · Suara: ${soundLabel}`;
  if (!audioUnlocked) {
    statusText += " ⚠️ (Klik halaman ini untuk aktifkan suara)";
  }
  els.captchaAlarmStatus.textContent = statusText;
}

function syncCaptchaAlarmControls() {
  if (els.captchaAlarmToggle) {
    els.captchaAlarmToggle.checked = captchaAlarmEnabled;
  }
  updateCaptchaAlarmStatus();
}

function saveCaptchaAlarmSettings() {
  try {
    localStorage.setItem(CAPTCHA_ALARM_ENABLED_KEY, String(captchaAlarmEnabled));
    if (captchaAlarmSoundData) {
      localStorage.setItem(CAPTCHA_ALARM_SOUND_DATA_KEY, captchaAlarmSoundData);
      localStorage.setItem(CAPTCHA_ALARM_SOUND_NAME_KEY, captchaAlarmSoundName || "custom-sound");
    } else {
      localStorage.removeItem(CAPTCHA_ALARM_SOUND_DATA_KEY);
      localStorage.removeItem(CAPTCHA_ALARM_SOUND_NAME_KEY);
    }
    return true;
  } catch {
    return false;
  }
}

async function playCaptchaAlarmSound({ force = false } = {}) {
  if (!force && !captchaAlarmEnabled) return;
  if (captchaAlarmSoundData) {
    try {
      const audio = new Audio(captchaAlarmSoundData);
      audio.volume = 1;
      await audio.play();
      return;
    } catch {}
  }
  playDefaultCaptchaAlarmTone();
}

let captchaAlarmCount = 0;

function triggerCaptchaAlarm() {
  // Sudah ada loop alarm berjalan — biarkan sampai selesai 3x
  if (captchaAlarmActive) return;
  captchaAlarmActive = true;
  captchaAlarmCount = 1;
  lastCaptchaAlarmAt = Date.now();

  // Bunyi langsung saat captcha pertama terdeteksi (loop ke-1)
  playCaptchaAlarmSound().catch(() => {});

  // Ulangi alarm 2x lagi (total 3x), tiap 6 detik
  if (captchaAlarmLoop) clearInterval(captchaAlarmLoop);
  captchaAlarmLoop = setInterval(() => {
    captchaAlarmCount++;
    if (captchaAlarmCount > 3) {
      stopCaptchaAlarm();
      return;
    }
    lastCaptchaAlarmAt = Date.now();
    playCaptchaAlarmSound().catch(() => {});
  }, 6000);
}

function stopCaptchaAlarm() {
  captchaAlarmActive = false;
  if (captchaAlarmLoop) {
    clearInterval(captchaAlarmLoop);
    captchaAlarmLoop = null;
  }
}

function updatePoolCollapseButton() {
  if (!els.poolCollapseBtn) return;
  els.poolCollapseBtn.textContent = poolListHidden ? "👁️ Tampilkan Daftar" : "🙈 Sembunyikan Daftar";
  els.poolCollapseBtn.setAttribute("aria-pressed", poolListHidden ? "true" : "false");
}

function setPoolListHidden(hidden) {
  poolListHidden = Boolean(hidden);
  sessionStorage.setItem(POOL_LIST_HIDDEN_KEY, String(poolListHidden));
  updatePoolCollapseButton();
  applyPoolListVisibility();
}

function applyPoolListVisibility() {
  if (!els.accountList) return;
  els.accountList.hidden = poolListHidden;
  if (poolListHidden) {
    els.selectAllChk.checked = false;
    if (els.archiveSelectedBtn) els.archiveSelectedBtn.style.display = "none";
    els.deleteSelectedBtn.style.display = "none";
  }
}

function updatePoolSelectionActionButtons() {
  if (!els.accountList) return;
  const checkedCount = els.accountList.querySelectorAll(".acc-select-chk:checked").length;
  const visible = checkedCount > 0 && !poolListHidden;
  if (els.archiveSelectedBtn) {
    els.archiveSelectedBtn.style.display = visible ? "inline-block" : "none";
  }
  if (els.deleteSelectedBtn) {
    els.deleteSelectedBtn.style.display = visible ? "inline-block" : "none";
  }
}

function switchAdminTab(tab) {
  const showPool = tab === "pool";
  const showArchive = tab === "archive";
  const showVoucher = tab === "voucher";
  const showTools = tab === "tools";
  const showIcloud = tab === "icloud";
  const showOwner = tab === "owner";
  const showFinance = tab === "finance";
  els.tabPanelPool.hidden = !showPool;
  els.tabPanelArchive.hidden = !showArchive;
  els.tabPanelVoucher.hidden = !showVoucher;
  els.tabPanelTools.hidden = !showTools;
  // Explicitly hide tools-only cards on other tabs
  if (els.addManualCard) els.addManualCard.hidden = !showTools;
  if (els.bulkImportCard) els.bulkImportCard.hidden = !showTools;
  if (els.tabPanelIcloud) els.tabPanelIcloud.hidden = !showIcloud;
  if (els.tabPanelOwner) els.tabPanelOwner.hidden = !showOwner;
  if (els.tabPanelFinance) els.tabPanelFinance.hidden = !showFinance;
  els.tabBtnPool.classList.toggle("active", showPool);
  els.tabBtnArchive.classList.toggle("active", showArchive);
  els.tabBtnVoucher.classList.toggle("active", showVoucher);
  els.tabBtnTools.classList.toggle("active", showTools);
  if (els.tabBtnIcloud) els.tabBtnIcloud.classList.toggle("active", showIcloud);
  if (els.tabBtnOwner) els.tabBtnOwner.classList.toggle("active", showOwner);
  if (els.tabBtnFinance) els.tabBtnFinance.classList.toggle("active", showFinance);

  if (showIcloud) {
    loadIcloudEmails();
    loadIcloudAccounts().catch(() => {});
  }
  if (showOwner) {
    loadOwnerSettings().catch(() => {});
  }
  if (showFinance) {
    loadFinanceDashboard().catch(() => {});
  }
}

function syncCreatorIntervalControls(minutes) {
  const value = String(minutes || 45);
  const presetValues = Array.from(els.creatorSchedulerInterval.options).map((opt) => opt.value);
  if (presetValues.includes(value)) {
    els.creatorSchedulerInterval.value = value;
    els.creatorSchedulerIntervalCustom.style.display = "none";
  } else {
    els.creatorSchedulerInterval.value = "custom";
    els.creatorSchedulerIntervalCustom.style.display = "inline-block";
    els.creatorSchedulerIntervalCustom.value = value;
  }
  if (!els.creatorSchedulerIntervalCustom.value) {
    els.creatorSchedulerIntervalCustom.value = value;
  }
}

function getCreatorSchedulerIntervalMinutes() {
  const selected = els.creatorSchedulerInterval.value;
  const rawValue = selected === "custom" ? els.creatorSchedulerIntervalCustom.value : selected;
  const minutes = Number(rawValue);
  if (!Number.isFinite(minutes) || minutes <= 0 || minutes > 1440) {
    throw new Error("Masukkan interval scheduler Pembuat Akun yang valid (1-1440 menit).");
  }
  return Math.round(minutes);
}

function syncReviveIntervalControls(minutes) {
  const value = String(minutes || 15);
  const presetValues = Array.from(els.reviveSchedulerInterval.options).map((opt) => opt.value);
  if (presetValues.includes(value)) {
    els.reviveSchedulerInterval.value = value;
    els.reviveSchedulerIntervalCustom.style.display = "none";
  } else {
    els.reviveSchedulerInterval.value = "custom";
    els.reviveSchedulerIntervalCustom.style.display = "inline-block";
    els.reviveSchedulerIntervalCustom.value = value;
  }
  if (!els.reviveSchedulerIntervalCustom.value) {
    els.reviveSchedulerIntervalCustom.value = value;
  }
}

function getReviveSchedulerIntervalMinutes() {
  const selected = els.reviveSchedulerInterval.value;
  const rawValue = selected === "custom" ? els.reviveSchedulerIntervalCustom.value : selected;
  const minutes = Number(rawValue);
  if (!Number.isFinite(minutes) || minutes <= 0 || minutes > 1440) {
    throw new Error("Masukkan interval scheduler Pemulih Akun yang valid (1-1440 menit).");
  }
  return Math.round(minutes);
}

function startStatusRefresh() {
  stopStatusRefresh();
  statusRefreshInterval = setInterval(() => {
    if (adminPass) loadBotStatus(false).catch(() => {});
  }, 15000);
}

function stopStatusRefresh() {
  if (statusRefreshInterval) {
    clearInterval(statusRefreshInterval);
    statusRefreshInterval = null;
  }
}

// ─── Login ──────────────────────────────────────────────────────────────────

// ─── Login ──────────────────────────────────────────────────────────────────

let adminRole = "owner";
let resellerNameStr = "";
let resellerQuotaNum = 0;
let resellerBalanceNum = 0;
let resellerCommissionNum = 0;
let allowBotFlag = true;
let allowPoolFlag = true;
let allowArchiveFlag = true;
let resellerCustomSrpVal = "";
let resellerCustomVipSrpVal = "";
let globalProPriceVal = 300000;
let globalVipPriceVal = 500000;
let fullAccessRequested = false;
let fullAccessGranted = false;
let fullAccessGrantedAt = null;

async function tryLogin(password) {
  try {
    const res = await fetch("/api/admin/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ password }),
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) throw new Error(data.error || "Login failed");
    adminPass = password;
    sessionStorage.setItem(ADMIN_KEY, password);
    
    // Save details
    adminRole = data.role || "owner";
    resellerNameStr = data.resellerName || "";
    resellerQuotaNum = data.quota !== null ? data.quota : 0;
    resellerBalanceNum = data.balance !== null ? data.balance : 0;
    resellerCommissionNum = data.totalCommission !== null ? data.totalCommission : 0;
    allowBotFlag = data.allowBot !== null ? data.allowBot : true;
    allowPoolFlag = data.allowPool !== null ? data.allowPool : true;
    allowArchiveFlag = data.allowArchive !== null ? data.allowArchive : true;

    resellerCustomSrpVal = data.customSrp !== null && data.customSrp !== undefined ? String(data.customSrp) : "";
    resellerCustomVipSrpVal = data.customVipSrp !== null && data.customVipSrp !== undefined ? String(data.customVipSrp) : "";
    globalProPriceVal = data.globalProPrice !== undefined ? data.globalProPrice : 300000;
    globalVipPriceVal = data.globalVipPrice !== undefined ? data.globalVipPrice : 500000;
    fullAccessRequested = data.fullAccessRequested || false;
    fullAccessGranted = data.fullAccessGranted || false;
    fullAccessGrantedAt = data.fullAccessGrantedAt || null;

    sessionStorage.setItem("weavy_admin_role", adminRole);
    sessionStorage.setItem("weavy_reseller_name", resellerNameStr);
    sessionStorage.setItem("weavy_reseller_quota", String(resellerQuotaNum));
    sessionStorage.setItem("weavy_reseller_balance", String(resellerBalanceNum));
    sessionStorage.setItem("weavy_reseller_commission", String(resellerCommissionNum));
    sessionStorage.setItem("weavy_allow_bot", String(allowBotFlag));
    sessionStorage.setItem("weavy_allow_pool", String(allowPoolFlag));
    sessionStorage.setItem("weavy_allow_archive", String(allowArchiveFlag));
    sessionStorage.setItem("weavy_reseller_custom_srp", resellerCustomSrpVal);
    sessionStorage.setItem("weavy_reseller_custom_vip_srp", resellerCustomVipSrpVal);
    sessionStorage.setItem("weavy_global_pro_price", String(globalProPriceVal));
    sessionStorage.setItem("weavy_global_vip_price", String(globalVipPriceVal));
    sessionStorage.setItem("weavy_full_access_requested", String(fullAccessRequested));
    sessionStorage.setItem("weavy_full_access_granted", String(fullAccessGranted));
    sessionStorage.setItem("weavy_full_access_granted_at", fullAccessGrantedAt || "");

    showAdmin();
    return true;
  } catch (err) {
    setLoginStatus(err.message, "error");
    return false;
  }
}

els.loginBtn.addEventListener("click", () => {
  const pass = els.password.value.trim();
  if (!pass) return;
  setLoginStatus("Logging in...");
  tryLogin(pass);
});

els.password.addEventListener("keydown", (e) => {
  if (e.key === "Enter") els.loginBtn.click();
});

const togglePassword = $("toggle-password");
if (togglePassword) {
  togglePassword.addEventListener("click", () => {
    const isPass = els.password.type === "password";
    els.password.type = isPass ? "text" : "password";
    togglePassword.textContent = isPass ? "🙈" : "👁️";
  });
}

els.logoutBtn.addEventListener("click", () => {
  adminPass = "";
  sessionStorage.removeItem(ADMIN_KEY);
  sessionStorage.removeItem("weavy_admin_role");
  sessionStorage.removeItem("weavy_reseller_name");
  sessionStorage.removeItem("weavy_reseller_quota");
  sessionStorage.removeItem("weavy_allow_bot");
  sessionStorage.removeItem("weavy_allow_pool");
  sessionStorage.removeItem("weavy_allow_archive");
  sessionStorage.removeItem("weavy_reseller_balance");
  sessionStorage.removeItem("weavy_reseller_commission");
  sessionStorage.removeItem("weavy_reseller_custom_srp");
  sessionStorage.removeItem("weavy_reseller_custom_vip_srp");
  sessionStorage.removeItem("weavy_global_pro_price");
  sessionStorage.removeItem("weavy_global_vip_price");
  sessionStorage.removeItem("weavy_full_access_requested");
  sessionStorage.removeItem("weavy_full_access_granted");
  sessionStorage.removeItem("weavy_full_access_granted_at");
  
  window.location.reload();
});

function applyRoleVisibility() {
  // Reset visibility
  els.tabBtnPool.style.display = "inline-block";
  els.tabBtnArchive.style.display = "inline-block";
  els.tabBtnVoucher.style.display = "inline-block";
  els.tabBtnTools.style.display = "inline-block";
  if (els.tabBtnOwner) els.tabBtnOwner.style.display = "none";
  if (els.tabBtnFinance) els.tabBtnFinance.style.display = "none";
  if (els.resellerInfoBar) els.resellerInfoBar.style.display = "none";
  if (els.fullAccessMitraControls) els.fullAccessMitraControls.style.display = "none";

  const resellerMarkupCard = document.getElementById("reseller-markup-card");
  if (resellerMarkupCard) resellerMarkupCard.style.display = "none";

  const addManualCard = document.getElementById("add-manual-card");
  const bulkImportCard = document.getElementById("bulk-import-card");
  const editForm = document.getElementById("edit-form");
  const toolsPanel = document.getElementById("tab-panel-tools");

  if (adminRole === "owner") {
    const walkReplacements = (element, replacements) => {
      if (!element) return;
      const walk = (node) => {
        if (node.nodeType === 3) {
          let val = node.nodeValue;
          for (const r of replacements) {
            val = val.replace(r.pattern, r.replacement);
          }
          node.nodeValue = val;
        } else if (node.nodeType === 1) {
          for (const child of node.childNodes) {
            walk(child);
          }
        }
      };
      walk(element);
    };

    if (toolsPanel) {
      walkReplacements(toolsPanel, [
        { pattern: /Daftar Provider/g, replacement: "Daftar Figma" },
        { pattern: /provider\.com/g, replacement: "figma.com" },
        { pattern: /Login Engine/g, replacement: "Login Weave" },
        { pattern: /engine\.provider\.com/g, replacement: "weave.figma.com" },
        { pattern: /Akun Provider/g, replacement: "Akun Figma" },
        { pattern: /Membuat akun Provider/g, replacement: "Membuat akun Figma" }
      ]);
    }

    if (addManualCard) {
      walkReplacements(addManualCard, [
        { pattern: /app\.provider\.ai/g, replacement: "app.weavy.ai" }
      ]);
    }
  } else {
    if (addManualCard) addManualCard.remove();
    if (bulkImportCard) bulkImportCard.remove();
    if (editForm) editForm.remove();
    
    const showToolsForMitra = (adminRole === "mitra" && allowBotFlag);
    if (!showToolsForMitra) {
      if (toolsPanel) toolsPanel.remove();
      els.tabBtnTools.style.display = "none";
    }
  }

  // Actions in pool
  const cleanBtn = els.cleanBtn;
  const syncBtn = els.syncBtn;
  if (cleanBtn) cleanBtn.style.display = "inline-block";
  if (syncBtn) syncBtn.style.display = "inline-block";

  if (adminRole === "owner") {
    if (els.tabBtnOwner) els.tabBtnOwner.style.display = "inline-block";
    if (els.tabBtnFinance) els.tabBtnFinance.style.display = "inline-block";
    const pricePaidWrapper = document.getElementById("vch-price-paid-wrapper");
    if (pricePaidWrapper) pricePaidWrapper.style.display = "block";
  } else if (adminRole === "kasir") {
    els.tabBtnArchive.style.display = "none";
    els.tabBtnTools.style.display = "none";
    
    if (cleanBtn) cleanBtn.style.display = "none";
    if (syncBtn) syncBtn.style.display = "none";
    if (els.archiveSelectedBtn) els.archiveSelectedBtn.style.display = "none";
    if (els.deleteSelectedBtn) els.deleteSelectedBtn.style.display = "none";
    
    const pricePaidWrapper = document.getElementById("vch-price-paid-wrapper");
    if (pricePaidWrapper) pricePaidWrapper.style.display = "block";
  } else if (adminRole === "mitra") {
    if (!allowArchiveFlag) {
      els.tabBtnArchive.style.display = "none";
    }
    
    if (!allowPoolFlag) {
      els.tabBtnPool.style.display = "none";
    } else {
      if (cleanBtn) cleanBtn.style.display = "none";
      if (syncBtn) syncBtn.style.display = "none";
      if (els.archiveSelectedBtn) els.archiveSelectedBtn.style.display = "none";
      if (els.deleteSelectedBtn) els.deleteSelectedBtn.style.display = "none";
    }

    if (!allowBotFlag) {
      els.tabBtnTools.style.display = "none";
    }

    if (els.resellerInfoBar) {
      els.resellerInfoBar.style.display = "block";
      els.infoResellerName.textContent = resellerNameStr;
      els.infoResellerQuota.textContent = String(resellerQuotaNum);
      if (els.infoResellerBalance) {
        els.infoResellerBalance.textContent = `Rp ${resellerBalanceNum.toLocaleString('id-ID')}`;
      }
      if (els.infoResellerCommission) {
        els.infoResellerCommission.textContent = `Rp ${resellerCommissionNum.toLocaleString('id-ID')}`;
      }
      // Full-access controls for mitra
      renderMitraFullAccessControls();
    }

    if (resellerMarkupCard) {
      resellerMarkupCard.style.display = "block";
      if (els.mitraCustomSrp) els.mitraCustomSrp.value = resellerCustomSrpVal;
      if (els.mitraCustomSrpVip) els.mitraCustomSrpVip.value = resellerCustomVipSrpVal;

      const proSrpDisp = document.getElementById("global-pro-srp-display");
      const vipSrpDisp = document.getElementById("global-vip-srp-display");
      if (proSrpDisp) proSrpDisp.textContent = `Rp ${globalProPriceVal.toLocaleString('id-ID')}`;
      if (vipSrpDisp) vipSrpDisp.textContent = `Rp ${globalVipPriceVal.toLocaleString('id-ID')}`;
    }

    const pricePaidWrapper = document.getElementById("vch-price-paid-wrapper");
    if (pricePaidWrapper) pricePaidWrapper.style.display = "none";
  }
}

function showAdmin() {
  els.loginScreen.hidden = true;
  els.adminScreen.hidden = false;
  setLoginStatus("");

  adminRole = sessionStorage.getItem("weavy_admin_role") || "owner";
  resellerNameStr = sessionStorage.getItem("weavy_reseller_name") || "";
  resellerQuotaNum = parseInt(sessionStorage.getItem("weavy_reseller_quota") || "0", 10);
  resellerBalanceNum = parseFloat(sessionStorage.getItem("weavy_reseller_balance") || "0");
  resellerCommissionNum = parseFloat(sessionStorage.getItem("weavy_reseller_commission") || "0");
  allowBotFlag = sessionStorage.getItem("weavy_allow_bot") !== "false";
  allowPoolFlag = sessionStorage.getItem("weavy_allow_pool") !== "false";
  allowArchiveFlag = sessionStorage.getItem("weavy_allow_archive") !== "false";
  resellerCustomSrpVal = sessionStorage.getItem("weavy_reseller_custom_srp") || "";
  resellerCustomVipSrpVal = sessionStorage.getItem("weavy_reseller_custom_vip_srp") || "";
  globalProPriceVal = parseFloat(sessionStorage.getItem("weavy_global_pro_price") || "300000");
  globalVipPriceVal = parseFloat(sessionStorage.getItem("weavy_global_vip_price") || "500000");
  fullAccessRequested = sessionStorage.getItem("weavy_full_access_requested") === "true";
  fullAccessGranted = sessionStorage.getItem("weavy_full_access_granted") === "true";
  fullAccessGrantedAt = sessionStorage.getItem("weavy_full_access_granted_at") || null;

  applyRoleVisibility();

  if (adminRole === "mitra") {
    if (allowPoolFlag) {
      switchAdminTab("pool");
    } else {
      switchAdminTab("voucher");
    }
  } else {
    switchAdminTab("pool");
  }

  syncCaptchaAlarmControls();
  updatePoolCollapseButton();
  refresh();
  refreshPromoStatus().catch((err) => console.error("refreshPromoStatus error:", err));
  loadPoolSettings().catch(() => {});
  refreshMaintenanceStatus().catch(() => {});
  loadIcloudAccounts().catch(() => {});

  if (adminRole === "owner" || (adminRole === "mitra" && allowBotFlag)) {
    loadBotStatus();
    connectSse();
    startStatusRefresh();
  }

  // Follow up: tampilkan popup voucher yang hampir expired
  scheduleExpiringPopup();
}

// ─── Follow up expiring vouchers ───────────────────────────────────────────

const SNOOZE_KEY_PREFIX = "weavy_expiring_snooze_";

function isSnoozed() {
  const until = sessionStorage.getItem(SNOOZE_KEY_PREFIX + adminRole);
  if (!until) return false;
  return Date.now() < parseInt(until, 10);
}

function setSnooze(hours = 24) {
  const until = Date.now() + hours * 60 * 60 * 1000;
  sessionStorage.setItem(SNOOZE_KEY_PREFIX + adminRole, String(until));
}

function scheduleExpiringPopup() {
  if (isSnoozed()) return;
  setTimeout(() => showExpiringPopup().catch(() => {}), 1500);
}

async function showExpiringPopup() {
  if (isSnoozed()) return;
  const threshold = parseInt(els.expiringThreshold.value, 10) || 2;
  let data;
  try {
    data = await api(`/api/admin/vouchers/expiring?days=${threshold}`);
  } catch (e) {
    return;
  }
  if (!data || !data.expiring || data.expiring.length === 0) return;
  if (isSnoozed()) return;

  // Render list
  els.expiringList.innerHTML = data.expiring.map(v => {
    const tierEmoji = v.tier === "vip" ? "👑" : "🎟️";
    const urgency = v.daysLeft <= 1
      ? `<span style="color:#f87171; font-weight:700;">⚠️ BESOK EXPIRED</span>`
      : `<span style="color:#fbbf24; font-weight:700;">Sisa ${v.daysLeft} hari</span>`;
    const wa = (v.whatsapp || "").replace(/[^\d+]/g, "");
    const waLink = wa ? `https://wa.me/${wa.replace(/^\+/, "")}` : "#";
    const source = (v.createdBy && v.createdBy.startsWith("mitra_"))
      ? `<span style="font-size:0.7rem; opacity:0.6;">Mitra: ${v.createdByName || v.createdBy}</span>`
      : `<span style="font-size:0.7rem; opacity:0.6;">Server</span>`;
    return `
      <div style="display:flex; justify-content:space-between; align-items:center; padding:10px 12px; border-bottom:1px solid #2c1f0d; gap:8px;">
        <div style="flex:1; min-width:0;">
          <div style="font-weight:700; display:flex; gap:6px; align-items:center;">
            ${tierEmoji} <span style="overflow:hidden; text-overflow:ellipsis;">${v.code}</span>
          </div>
          <div style="font-size:0.75rem; opacity:0.8;">📱 ${v.whatsapp || "-"}</div>
          <div style="font-size:0.7rem; opacity:0.6;">⏰ ${new Date(v.expiresAt).toLocaleString("id-ID")}</div>
          ${source}
        </div>
        <div style="text-align:right; display:flex; flex-direction:column; gap:4px; align-items:flex-end;">
          ${urgency}
          ${wa ? `<a href="${waLink}" target="_blank" rel="noopener" style="font-size:0.7rem; padding:3px 8px; background:#22c55e; color:white; border-radius:4px; text-decoration:none;">💬 Chat</a>` : ""}
        </div>
      </div>
    `;
  }).join("");

  const isMitra = (adminRole === "mitra");
  const descEl = $("expiring-modal-desc");
  if (descEl) {
    descEl.textContent = isMitra
      ? `Ada ${data.total} member Anda yang masa aktifnya tinggal ≤ ${threshold} hari. Segera hubungi untuk perpanjang membership!`
      : `Ada ${data.total} voucher yang masa aktifnya tinggal ≤ ${threshold} hari.${isMitra ? "" : " Termasuk yang dibuat oleh mitra."}`;
  }

  els.expiringModal.classList.add("active");
}

function hideExpiringPopup() {
  if (els.expiringModal) els.expiringModal.classList.remove("active");
}

// ─── Account list ────────────────────────────────────────────────────────────

async function refresh() {
  try {
    if (adminRole === "mitra") {
      const profile = await api("/api/admin/reseller/profile").catch(() => null);
      if (profile) {
        resellerBalanceNum = profile.balance;
        resellerCommissionNum = profile.totalCommission;
        resellerCustomSrpVal = profile.customSrp !== null && profile.customSrp !== undefined ? String(profile.customSrp) : "";
        resellerCustomVipSrpVal = profile.customVipSrp !== null && profile.customVipSrp !== undefined ? String(profile.customVipSrp) : "";
        globalProPriceVal = profile.globalProPrice;
        globalVipPriceVal = profile.globalVipPrice;

        sessionStorage.setItem("weavy_reseller_balance", String(resellerBalanceNum));
        sessionStorage.setItem("weavy_reseller_commission", String(resellerCommissionNum));
        sessionStorage.setItem("weavy_reseller_custom_srp", resellerCustomSrpVal);
        sessionStorage.setItem("weavy_reseller_custom_vip_srp", resellerCustomVipSrpVal);
        sessionStorage.setItem("weavy_global_pro_price", String(globalProPriceVal));
        sessionStorage.setItem("weavy_global_vip_price", String(globalVipPriceVal));

        applyRoleVisibility();
      }
    }

    const [accountsRes, archivedAccountsRes] = await Promise.allSettled([
      api("/api/admin/accounts"),
      api("/api/admin/accounts/archive"),
    ]);

    if (accountsRes.status === "rejected" && accountsRes.reason.message === "Unauthorized") {
      throw new Error("Unauthorized");
    }

    const accounts = accountsRes.status === "fulfilled" ? accountsRes.value.accounts : [];
    const archivedAccounts = archivedAccountsRes.status === "fulfilled" ? archivedAccountsRes.value.accounts : [];

    renderStats(accounts, archivedAccounts);
    currentAccounts = accounts;
    renderList(accounts);
    renderArchiveList(archivedAccounts);
    els.poolSize.textContent = `${accounts.length} aktif · ${archivedAccounts.length} archive`;
    refreshVouchers().catch((err) => console.error("refreshVouchers error:", err));
    refreshMaintenanceStatus().catch(() => {});
  } catch (err) {
    if (err.message === "Unauthorized") {
      sessionStorage.setItem("login_flash_message", "Session expired, login lagi");
      els.logoutBtn.click();
    } else {
      console.error(err);
    }
  }
}

function renderStats(accounts, archivedAccounts = []) {
  const total = accounts.length;
  const active = accounts.filter((a) => !a.expired).length;
  const expired = accounts.filter((a) => a.expired).length;
  const archived = archivedAccounts.length;
  const totalRuns = [...accounts, ...archivedAccounts].reduce((s, a) => s + (a.runs || 0), 0);
  els.stats.innerHTML = `
    <div class="stat"><div class="stat-num">${total + archived}</div><div class="stat-label">Total Akun</div></div>
    <div class="stat"><div class="stat-num good">${active}</div><div class="stat-label">Pool Aktif</div></div>
    <div class="stat"><div class="stat-num">${archived}</div><div class="stat-label">Archive</div></div>
    <div class="stat"><div class="stat-num bad">${expired}</div><div class="stat-label">Expired</div></div>
    <div class="stat"><div class="stat-num">${totalRuns}</div><div class="stat-label">Total Runs</div></div>
  `;
}

function renderList(accounts) {
  if (els.selectAllChk) els.selectAllChk.checked = false;
  if (els.archiveSelectedBtn) els.archiveSelectedBtn.style.display = "none";
  if (els.deleteSelectedBtn) els.deleteSelectedBtn.style.display = "none";

  if (!accounts.length) {
    els.accountList.innerHTML = `<div class="empty-accounts">Belum ada akun. Tambahkan di bawah atau gunakan Auto Token Bot.</div>`;
    applyPoolListVisibility();
    return;
  }
  els.accountList.innerHTML = "";
  for (const a of accounts) {
    const row = document.createElement("div");
    row.className = `account-row ${a.expired ? "expired" : ""}`;
    row.innerHTML = `
      <div style="display: flex; align-items: center;">
        <input type="checkbox" class="acc-select-chk" data-id="${a.id}" style="width: 18px; height: 18px; cursor: pointer;" />
      </div>
      <div class="acc-info">
        <div class="acc-label">${escapeHtml(a.label)}</div>
        <div class="acc-meta">
          <span>${escapeHtml(a.email || "?")}</span>
          <span class="dot">·</span>
          <span class="${a.expired ? "exp-bad" : "exp-ok"}">${formatTimeLeft(a.exp)}</span>
          <span class="dot">·</span>
          <span>runs: ${a.runs || 0}/${a.maxRuns || 3}</span>
          <span class="dot">·</span>
          <span>credits: ${a.credits || 150}</span>
          ${a.expired ? `<span class="dot">·</span><span class="badge" style="background:#fbbf24;color:#000;font-size:0.65rem;padding:1px 5px;border-radius:3px;">EXPIRED</span>` : ""}
          <span class="dot">·</span>
          <span>recipe: <code>${escapeHtml(a.recipeId || "default")}</code></span>
        </div>
        <div class="acc-meta">
          <span class="muted-inline">${escapeHtml(a.tokenPreview)}</span>
        </div>
      </div>
      <div class="acc-actions" style="${adminRole === 'owner' ? '' : 'display: none;'}">
        ${a.expired && a.email ? `<button type="button" class="ghost small revive-btn" data-act="revive" data-id="${a.id}" data-email="${escapeHtml(a.email)}" style="color:#fbbf24;border-color:#fbbf24;" title="Revive akun via Figma Sign-In">🔄</button>` : ""}
        <button type="button" class="ghost small" data-act="edit" data-id="${a.id}">✏️</button>
        <button type="button" class="ghost small danger" data-act="del" data-id="${a.id}">🗑️</button>
      </div>
    `;
    els.accountList.appendChild(row);
  }
  applyPoolListVisibility();
}

els.poolCollapseBtn.addEventListener("click", () => {
  setPoolListHidden(!poolListHidden);
});

function renderArchiveList(accounts) {
  els.archiveCount.textContent = String(accounts.length);
  if (els.archiveTabCount) {
    els.archiveTabCount.textContent = String(accounts.length);
  }
  if (!accounts.length) {
    els.archiveList.innerHTML = `<div class="empty-accounts">Belum ada akun archive. Akun dengan runs maksimal akan pindah ke sini otomatis.</div>`;
    return;
  }

  els.archiveList.innerHTML = "";
  for (const a of accounts) {
    const row = document.createElement("div");
    row.className = "account-row expired";
    row.style.gridTemplateColumns = "1fr auto";
    const isSameMonth = a.archivedMonth === new Date().toISOString().slice(0, 7);
    row.innerHTML = `
      <div class="acc-info">
        <div class="acc-label" style="display:flex; align-items:center; gap:8px;">
          <span>${escapeHtml(a.label)}</span>
          <span class="badge badge-idle" style="animation:none;">ARCHIVE</span>
        </div>
        <div class="acc-meta">
          <span>${escapeHtml(a.email || "?")}</span>
          <span class="dot">·</span>
          <span>runs: ${a.runs || 0}</span>
          <span class="dot">·</span>
          <span>bulan archive: <code>${escapeHtml(a.archivedMonth || "-")}</code></span>
          <span class="dot">·</span>
          <span>${isSameMonth ? "Menunggu reset otomatis" : "Siap dipulihkan"}</span>
        </div>
        <div class="acc-meta">
          <span>recipe: <code>${escapeHtml(a.recipeId || "default")}</code></span>
          <span class="dot">·</span>
          <span class="muted-inline">${escapeHtml(a.tokenPreview)}</span>
        </div>
      </div>
      <div class="acc-actions">
        <button type="button" class="ghost small" data-restore-id="${a.id}">♻️ Pulihkan</button>
      </div>
    `;
    els.archiveList.appendChild(row);
  }
}

els.tabBtnPool.addEventListener("click", () => switchAdminTab("pool"));
els.tabBtnArchive.addEventListener("click", () => switchAdminTab("archive"));
els.tabBtnVoucher.addEventListener("click", () => switchAdminTab("voucher"));
els.tabBtnTools.addEventListener("click", () => switchAdminTab("tools"));
if (els.tabBtnIcloud) els.tabBtnIcloud.addEventListener("click", () => switchAdminTab("icloud"));
if (els.tabBtnOwner) els.tabBtnOwner.addEventListener("click", () => switchAdminTab("owner"));
if (els.tabBtnFinance) els.tabBtnFinance.addEventListener("click", () => switchAdminTab("finance"));

// ═══════════════════════════════════════════════════════
// 💰 FINANCE DASHBOARD
// ═══════════════════════════════════════════════════════

const FINANCE_HEADERS = { "X-Admin-Password": () => sessionStorage.getItem(ADMIN_KEY) || adminPass };

let financeReportMode = "daily";
let financeRefreshTimer = null;

function formatRp(n) {
  return "Rp " + Math.abs(n || 0).toLocaleString("id-ID");
}

function formatTime(iso) {
  if (!iso) return "—";
  const d = new Date(iso);
  return d.toLocaleDateString("id-ID", { day: "2-digit", month: "short", year: "numeric" }) +
    " " + d.toLocaleTimeString("id-ID", { hour: "2-digit", minute: "2-digit" });
}

function finTypeBadge(type) {
  const map = {
    voucher_sale: ["🛒 Penjualan", "#22c55e"],
    topup: ["💸 Topup", "#3b82f6"],
    commission: ["💰 Komisi", "#f59e0b"],
    adjustment: ["⚙️ Adjustment", "#a855f7"],
    refund: ["↩️ Refund", "#ef4444"],
  };
  const [label, color] = map[type] || [type, "#888"];
  return `<span style="color:${color};font-weight:600;">${label}</span>`;
}

async function loadFinanceSummary() {
  try {
    const res = await fetch("/api/admin/finance/summary", { headers: { "X-Admin-Password": FINANCE_HEADERS["X-Admin-Password"]() } });
    if (!res.ok) throw new Error("Gagal memuat summary");
    const data = await res.json();
    if (!data.ok) throw new Error(data.error || "Unknown error");

    els.finTodayIncome.textContent = formatRp(data.today?.income || 0);
    els.finTodayTxn.textContent = `${data.today?.net >= 0 ? "+" : ""}${formatRp(data.today?.net || 0)} · ${data.transactionCount || 0} transaksi`;
    els.finWeekIncome.textContent = formatRp(data.week?.income || 0);
    els.finWeekTxn.textContent = `Net: ${data.week?.net >= 0 ? "+" : ""}${formatRp(data.week?.net || 0)}`;
    els.finMonthIncome.textContent = formatRp(data.month?.income || 0);
    els.finMonthTxn.textContent = `Net: ${data.month?.net >= 0 ? "+" : ""}${formatRp(data.month?.net || 0)}`;
    els.finTotalIncome.textContent = formatRp(data.total?.income || 0);
    els.finBalance.textContent = `Balance: ${formatRp(data.runningBalance || 0)}`;

    // Per-reseller mini cards
    if (data.perReseller && data.perReseller.length > 0) {
      els.finResellerCards.innerHTML = data.perReseller.map(r =>
        `<div style="background:rgba(255,255,255,0.03);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-size:0.7rem;min-width:140px;">
          <div style="color:var(--muted);">👤 ${r.resellerName || r.resellerId}</div>
          <div style="color:#22c55e;font-weight:600;">${formatRp(r.totalIncome)}</div>
          <div style="color:var(--muted);font-size:0.6rem;">${r.voucherCount} voucher</div>
        </div>`
      ).join("");
    } else {
      els.finResellerCards.innerHTML = `<span style="font-size:0.7rem;color:var(--muted);">Belum ada transaksi mitra.</span>`;
    }

    // Populate reseller dropdown for topup
    const ownerRes = await fetch("/api/admin/owner/settings", { headers: { "X-Admin-Password": FINANCE_HEADERS["X-Admin-Password"]() } });
    if (ownerRes.ok) {
      const ownerData = await ownerRes.json();
      if (ownerData.resellers && ownerData.resellers.length > 0) {
        els.finTopupReseller.innerHTML = ownerData.resellers.map(r =>
          `<option value="${r.id}">${r.name} (Saldo: ${formatRp(r.balance || 0)})</option>`
        ).join("");
      }
    }

    // Update actor filter dropdown with resellers
    if (data.perReseller && data.perReseller.length > 0) {
      const existingOpts = new Set(Array.from(els.finFilterActor.options).map(o => o.value));
      for (const r of data.perReseller) {
        if (!existingOpts.has(r.resellerId)) {
          const opt = document.createElement("option");
          opt.value = r.resellerId;
          opt.textContent = `Mitra: ${r.resellerName || r.resellerId}`;
          els.finFilterActor.appendChild(opt);
          existingOpts.add(r.resellerId);
        }
      }
    }

    els.finLastUpdated.textContent = `Diperbarui: ${new Date().toLocaleTimeString("id-ID")}`;
  } catch (err) {
    console.error("[Finance] Summary error:", err);
  }
}

async function loadFinanceTransactions(mode, extraParams = {}) {
  try {
    let url;
    const params = new URLSearchParams();
    if (extraParams.limit) params.set("limit", extraParams.limit);

    if (mode === "daily") {
      url = "/api/admin/finance/report/daily";
      const date = els.finFilterDate.value || new Date().toISOString().split("T")[0];
      params.set("date", date);
    } else if (mode === "weekly") {
      url = "/api/admin/finance/report/weekly";
      if (extraParams.week) params.set("week", extraParams.week);
    } else if (mode === "monthly") {
      url = "/api/admin/finance/report/monthly";
      if (extraParams.month) params.set("month", extraParams.month);
    } else {
      url = "/api/admin/finance/transactions";
      if (extraParams.from) params.set("from", extraParams.from);
      if (extraParams.to) params.set("to", extraParams.to);
    }

    // Apply common filters
    const type = els.finFilterType.value;
    const actor = els.finFilterActor.value;
    const search = els.finFilterSearch.value.trim();
    if (type) params.set("type", type);
    if (actor) params.set("actor", actor);
    if (search) params.set("search", search);

    url += "?" + params.toString();

    const res = await fetch(url, { headers: { "X-Admin-Password": FINANCE_HEADERS["X-Admin-Password"]() } });
    if (!res.ok) throw new Error("Gagal memuat transaksi");
    const data = await res.json();
    if (!data.ok) throw new Error(data.error || "Unknown error");

    const txns = data.transactions || [];

    // Render report summary
    if (mode !== "logs") {
      els.finReportSummary.innerHTML = `
        <div class="stat-card" style="flex:1;min-width:100px;padding:8px 12px;background:rgba(34,197,94,0.05);border:1px solid #22c55e33;border-radius:8px;text-align:center;">
          <div style="font-size:0.6rem;color:var(--muted);">Pendapatan</div>
          <div style="font-size:1rem;font-weight:700;color:#22c55e;">${formatRp(data.income || 0)}</div>
        </div>
        <div class="stat-card" style="flex:1;min-width:100px;padding:8px 12px;background:rgba(239,68,68,0.05);border:1px solid #ef444433;border-radius:8px;text-align:center;">
          <div style="font-size:0.6rem;color:var(--muted);">Pengeluaran</div>
          <div style="font-size:1rem;font-weight:700;color:#ef4444;">${formatRp(data.expense || 0)}</div>
        </div>
        <div class="stat-card" style="flex:1;min-width:100px;padding:8px 12px;background:rgba(168,85,247,0.05);border:1px solid #a855f733;border-radius:8px;text-align:center;">
          <div style="font-size:0.6rem;color:var(--muted);">Net</div>
          <div style="font-size:1rem;font-weight:700;color:${(data.net || 0) >= 0 ? '#22c55e' : '#ef4444'};">${formatRp(data.net || 0)}</div>
        </div>
        <div class="stat-card" style="flex:1;min-width:100px;padding:8px 12px;background:rgba(59,130,246,0.05);border:1px solid #3b82f633;border-radius:8px;text-align:center;">
          <div style="font-size:0.6rem;color:var(--muted);">Transaksi</div>
          <div style="font-size:1rem;font-weight:700;color:#3b82f6;">${data.transactionCount || txns.length}</div>
        </div>
      `;

      // By-type breakdown
      if (data.byType && Object.keys(data.byType).length > 0) {
        const byTypeHtml = Object.entries(data.byType).map(([type, info]) =>
          `<span style="background:rgba(255,255,255,0.04);padding:2px 8px;border-radius:4px;font-size:0.65rem;">
            ${finTypeBadge(type)}: ${info.count}x · ${formatRp(info.amount)}
          </span>`
        ).join(" ");
        els.finReportSummary.innerHTML += `<div style="flex-basis:100%;margin-top:4px;">${byTypeHtml}</div>`;
      }
    } else {
      els.finReportSummary.innerHTML = `
        <div class="stat-card" style="flex:1;min-width:100px;padding:8px 12px;background:rgba(34,197,94,0.05);border:1px solid #22c55e33;border-radius:8px;text-align:center;">
          <div style="font-size:0.6rem;color:var(--muted);">Total Ditemukan</div>
          <div style="font-size:1rem;font-weight:700;color:#3b82f6;">${data.total || 0}</div>
        </div>
        <div class="stat-card" style="flex:1;min-width:100px;padding:8px 12px;background:rgba(34,197,94,0.05);border:1px solid #22c55e33;border-radius:8px;text-align:center;">
          <div style="font-size:0.6rem;color:var(--muted);">Total Pendapatan</div>
          <div style="font-size:1rem;font-weight:700;color:#22c55e;">${formatRp(data.incomeAmount || 0)}</div>
        </div>
        <div class="stat-card" style="flex:1;min-width:100px;padding:8px 12px;background:rgba(239,68,68,0.05);border:1px solid #ef444433;border-radius:8px;text-align:center;">
          <div style="font-size:0.6rem;color:var(--muted);">Total Pengeluaran</div>
          <div style="font-size:1rem;font-weight:700;color:#ef4444;">${formatRp(data.expenseAmount || 0)}</div>
        </div>
      `;
    }

    // Render transaction table
    if (txns.length === 0) {
      els.finTxnBody.innerHTML = `<tr><td colspan="6" style="text-align:center;padding:32px;color:var(--muted);">Tidak ada transaksi untuk periode ini.</td></tr>`;
    } else {
      els.finTxnBody.innerHTML = txns.map(t => `
        <tr style="border-bottom:1px solid rgba(255,255,255,0.04);">
          <td style="padding:6px 8px;font-size:0.7rem;color:var(--muted);white-space:nowrap;">${formatTime(t.timestamp)}</td>
          <td style="padding:6px 8px;font-size:0.75rem;">${finTypeBadge(t.type)}</td>
          <td style="padding:6px 8px;font-size:0.75rem;max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${t.description}">${t.description}</td>
          <td style="padding:6px 8px;font-size:0.7rem;font-family:monospace;color:var(--muted);">${t.voucherCode || "—"}</td>
          <td style="padding:6px 8px;font-size:0.7rem;">${t.category ? t.category.toUpperCase() : "—"}</td>
          <td style="padding:6px 8px;text-align:right;font-size:0.8rem;font-weight:600;color:${t.amount >= 0 ? '#22c55e' : '#ef4444'};white-space:nowrap;">${t.amount >= 0 ? "+" : ""}${formatRp(t.amount)}</td>
        </tr>
      `).join("");
    }

    els.finPagination.textContent = `Menampilkan ${txns.length} transaksi`;
  } catch (err) {
    console.error("[Finance] Transactions error:", err);
    els.finTxnBody.innerHTML = `<tr><td colspan="6" style="text-align:center;padding:32px;color:#ef4444;">Gagal memuat: ${err.message}</td></tr>`;
  }
}

async function loadFinanceDashboard() {
  await loadFinanceSummary();
  await loadFinanceTransactions(financeReportMode);
}

// Report mode buttons
document.addEventListener("click", (e) => {
  const btn = e.target.closest(".finance-report-btn");
  if (!btn) return;
  document.querySelectorAll(".finance-report-btn").forEach(b => b.classList.remove("active"));
  btn.classList.add("active");
  financeReportMode = btn.dataset.report;
  loadFinanceTransactions(financeReportMode);
});

// Filter change handlers
if (els.finFilterDate) {
  els.finFilterDate.value = new Date().toISOString().split("T")[0];
  els.finFilterDate.addEventListener("change", () => {
    if (financeReportMode === "daily") loadFinanceTransactions("daily");
    else loadFinanceTransactions(financeReportMode, { from: els.finFilterDate.value + "T00:00:00.000Z" });
  });
}
if (els.finFilterType) els.finFilterType.addEventListener("change", () => loadFinanceTransactions(financeReportMode));
if (els.finFilterActor) els.finFilterActor.addEventListener("change", () => loadFinanceTransactions(financeReportMode));
if (els.finFilterSearch) {
  let searchTimer;
  els.finFilterSearch.addEventListener("input", () => {
    clearTimeout(searchTimer);
    searchTimer = setTimeout(() => loadFinanceTransactions(financeReportMode), 400);
  });
}
if (els.finRefreshBtn) els.finRefreshBtn.addEventListener("click", () => loadFinanceDashboard());

// Topup handler
if (els.finTopupBtn) {
  els.finTopupBtn.addEventListener("click", async () => {
    const resellerId = els.finTopupReseller.value;
    const amount = parseInt(els.finTopupAmount.value, 10);
    const note = els.finTopupNote.value.trim();

    if (!resellerId) { showToast("Pilih mitra terlebih dahulu.", "error"); return; }
    if (!amount || amount < 1000) { showToast("Jumlah minimal Rp 1.000.", "error"); return; }

    els.finTopupBtn.disabled = true;
    els.finTopupBtn.textContent = "⏳ Memproses...";
    try {
      const res = await fetch("/api/admin/finance/topup", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Admin-Password": FINANCE_HEADERS["X-Admin-Password"](),
        },
        body: JSON.stringify({ resellerId, amount, note }),
      });
      const data = await res.json();
      if (data.ok) {
        showToast(data.msg, "success");
        els.finTopupAmount.value = "";
        els.finTopupNote.value = "";
        els.finTopupFeedback.innerHTML = `<span style="color:#22c55e;">✅ ${data.msg}</span>`;
        setTimeout(() => { els.finTopupFeedback.innerHTML = ""; }, 5000);
        loadFinanceDashboard();
      } else {
        showToast(data.error || "Gagal topup.", "error");
        els.finTopupFeedback.innerHTML = `<span style="color:#ef4444;">❌ ${data.error}</span>`;
      }
    } catch (err) {
      showToast("Gagal: " + err.message, "error");
    } finally {
      els.finTopupBtn.disabled = false;
      els.finTopupBtn.textContent = "💰 Topup";
    }
  });
}

// Voucher search filters
const _vchSearchCode = $("vch-search-code");
const _vchSearchWa = $("vch-search-whatsapp");
const _vchSearchTier = $("vch-search-tier");
const _vchSearchExpiry = $("vch-search-expiry");
const _vchSearchCreator = $("vch-search-creator");
const _vchSearchBtn = $("vch-search-btn");
const _vchSearchReset = $("vch-search-reset");

if (_vchSearchBtn) _vchSearchBtn.addEventListener("click", applyVoucherFilters);
if (_vchSearchReset) _vchSearchReset.addEventListener("click", () => {
  if (_vchSearchCode) _vchSearchCode.value = "";
  if (_vchSearchWa) _vchSearchWa.value = "";
  if (_vchSearchTier) _vchSearchTier.value = "";
  if (_vchSearchExpiry) _vchSearchExpiry.value = "";
  if (_vchSearchCreator) _vchSearchCreator.value = "";
  applyVoucherFilters();
});
if (_vchSearchCode) _vchSearchCode.addEventListener("keydown", (e) => { if (e.key === "Enter") applyVoucherFilters(); });
if (_vchSearchWa) _vchSearchWa.addEventListener("keydown", (e) => { if (e.key === "Enter") applyVoucherFilters(); });

// Expiring popup
if (els.expiringCloseBtn) els.expiringCloseBtn.addEventListener("click", hideExpiringPopup);
if (els.expiringSnoozeBtn) els.expiringSnoozeBtn.addEventListener("click", () => {
  setSnooze(24);
  hideExpiringPopup();
});
if (els.expiringRefreshBtn) els.expiringRefreshBtn.addEventListener("click", () => showExpiringPopup().catch(() => {}));
if (els.expiringThreshold) els.expiringThreshold.addEventListener("change", () => showExpiringPopup().catch(() => {}));

if (els.captchaAlarmToggle) {
  els.captchaAlarmToggle.addEventListener("change", () => {
    captchaAlarmEnabled = els.captchaAlarmToggle.checked;
    if (!captchaAlarmEnabled) stopCaptchaAlarm();
    saveCaptchaAlarmSettings();
    updateCaptchaAlarmStatus();
  });
}

if (els.captchaAlarmSoundFile) {
  els.captchaAlarmSoundFile.addEventListener("change", async (event) => {
    const file = event.target.files?.[0];
    if (!file) return;

    const allowedTypes = ["audio/mpeg", "audio/mp3", "audio/wav", "audio/x-wav"];
    const hasAllowedExtension = /\.(mp3|wav)$/i.test(file.name);
    if (!allowedTypes.includes(file.type) && !hasAllowedExtension) {
      alert("File alarm harus berformat .mp3 atau .wav");
      event.target.value = "";
      return;
    }

    if (file.size > 1024 * 1024) {
      alert("Ukuran file alarm maksimal 1 MB agar aman disimpan di browser.");
      event.target.value = "";
      return;
    }

    try {
      const dataUrl = await new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => resolve(String(reader.result || ""));
        reader.onerror = () => reject(new Error("Gagal membaca file suara."));
        reader.readAsDataURL(file);
      });

      captchaAlarmSoundData = dataUrl;
      captchaAlarmSoundName = file.name;
      if (!saveCaptchaAlarmSettings()) {
        captchaAlarmSoundData = "";
        captchaAlarmSoundName = "";
        throw new Error("Gagal menyimpan custom sound di browser. Coba file yang lebih kecil.");
      }
      updateCaptchaAlarmStatus(`Custom sound aktif: ${file.name}`);
      await playCaptchaAlarmSound({ force: true });
    } catch (err) {
      alert(err.message || "Gagal menyimpan custom sound.");
    } finally {
      event.target.value = "";
    }
  });
}

if (els.captchaAlarmResetBtn) {
  els.captchaAlarmResetBtn.addEventListener("click", () => {
    captchaAlarmSoundData = "";
    captchaAlarmSoundName = "";
    saveCaptchaAlarmSettings();
    updateCaptchaAlarmStatus("Suara alarm dikembalikan ke default beep.");
  });
}

if (els.captchaAlarmTestBtn) {
  els.captchaAlarmTestBtn.addEventListener("click", async () => {
    updateCaptchaAlarmStatus("Menjalankan test sound alarm CAPTCHA...");
    await playCaptchaAlarmSound({ force: true });
    setTimeout(() => updateCaptchaAlarmStatus(), 1000);
  });
}

// ─── Add / edit / bulk ──────────────────────────────────────────────────────

els.refreshBtn.addEventListener("click", refresh);

els.syncBtn.addEventListener("click", async () => {
  els.syncBtn.disabled = true;
  els.syncBtn.textContent = "☁️ Syncing...";
  try {
    const res = await api("/api/admin/accounts/sync", { method: "POST" });
    alert("Sinkronisasi Sukses: " + res.msg);
    refresh();
  } catch (err) {
    alert("Gagal Sinkronisasi: " + err.message);
  } finally {
    els.syncBtn.disabled = false;
    els.syncBtn.textContent = "☁️ Sync Server";
  }
});

// ─── Pool Settings Handlers ─────────────────────────────────────────────────

// Load pool settings on page init
async function loadPoolSettings() {
  try {
    const res = await fetch("/api/admin/pool/settings", { headers: buildAuthHeaders() });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
    if (data.ok && els.poolMaxRunsInput) {
      els.poolMaxRunsInput.value = data.defaultMaxRuns || 3;
      els.poolMonthlyCreditsInput.value = data.monthlyCredits || 150;
    }
  } catch (err) {
    console.error("Load pool settings error:", err.message);
  }
}

if (els.poolSettingsSaveBtn) {
  els.poolSettingsSaveBtn.addEventListener("click", async () => {
    els.poolSettingsSaveBtn.disabled = true;
    try {
      const maxRuns = parseInt(els.poolMaxRunsInput.value) || 3;
      const monthlyCredits = parseInt(els.poolMonthlyCreditsInput.value) || 150;
      const res = await fetch("/api/admin/pool/settings", {
        method: "PUT",
        headers: buildAuthHeaders(),
        body: JSON.stringify({ maxRuns, monthlyCredits }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
      if (els.poolSettingsMsg) {
        els.poolSettingsMsg.textContent = "✅ Pengaturan pool tersimpan!";
        els.poolSettingsMsg.style.color = "#34d399";
        setTimeout(() => { els.poolSettingsMsg.textContent = ""; }, 3000);
      }
      refresh();
    } catch (err) {
      if (els.poolSettingsMsg) {
        els.poolSettingsMsg.textContent = "❌ Gagal: " + err.message;
        els.poolSettingsMsg.style.color = "#ef4444";
      }
    } finally {
      els.poolSettingsSaveBtn.disabled = false;
    }
  });
}

if (els.poolResetMonthlyBtn) {
  els.poolResetMonthlyBtn.addEventListener("click", async () => {
    if (!await showConfirm("Reset semua akun pool? Ini akan: un-expired semua akun, runs → 0, kredit → 150. Lanjutkan?")) return;
    els.poolResetMonthlyBtn.disabled = true;
    try {
      const res = await fetch("/api/admin/pool/reset-monthly", {
        method: "POST",
        headers: buildAuthHeaders(),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
      if (data.ok) {
        if (els.poolSettingsMsg) {
          els.poolSettingsMsg.textContent = `✅ ${data.reset} akun di-reset (${data.month})`;
          els.poolSettingsMsg.style.color = "#34d399";
          setTimeout(() => { els.poolSettingsMsg.textContent = ""; }, 5000);
        }
        refresh();
      } else {
        throw new Error(data.error || "Unknown error");
      }
    } catch (err) {
      if (els.poolSettingsMsg) {
        els.poolSettingsMsg.textContent = "❌ Gagal reset: " + err.message;
        els.poolSettingsMsg.style.color = "#ef4444";
      }
    } finally {
      els.poolResetMonthlyBtn.disabled = false;
    }
  });
}

els.cleanBtn.addEventListener("click", async () => {
  if (!await showConfirm("Bersihkan semua akun yang expired/habis jatah generate?")) return;
  try {
    const res = await api("/api/admin/accounts/clean", { method: "POST" });
    alert(`Berhasil menghapus ${res.cleaned} akun expired.`);
    refresh();
  } catch (err) {
    alert("Gagal membersihkan: " + err.message);
  }
});

els.addBtn.addEventListener("click", async () => {
  const token = els.addToken.value.trim();
  if (!token) return alert("Token wajib diisi");
  try {
    await api("/api/admin/accounts", {
      method: "POST",
      body: JSON.stringify({ token, recipeId: els.addRecipe.value.trim(), label: els.addLabel.value.trim() }),
    });
    els.addToken.value = ""; els.addRecipe.value = ""; els.addLabel.value = "";
    refresh();
  } catch (err) { alert(err.message); }
});

els.bulkBtn.addEventListener("click", async () => {
  const lines = els.bulkText.value.split("\n").map((s) => s.trim()).filter(Boolean);
  if (!lines.length) return alert("Tidak ada baris");
  try {
    const result = await api("/api/admin/accounts/bulk", { method: "POST", body: JSON.stringify({ lines }) });
    let msg = `${result.added} akun berhasil ditambahkan`;
    if (result.errors?.length) {
      msg += `\n\n${result.errors.length} error:\n` + result.errors.map((e) => `- ${e.line}: ${e.error}`).join("\n");
    }
    alert(msg);
    els.bulkText.value = "";
    refresh();
  } catch (err) { alert(err.message); }
});

els.cancelEditBtn.addEventListener("click", () => { els.editForm.hidden = true; });

els.saveEditBtn.addEventListener("click", async () => {
  const id = els.editId.value;
  const patch = { recipeId: els.editRecipe.value.trim(), label: els.editLabel.value.trim() };
  const newToken = els.editToken.value.trim();
  if (newToken) patch.token = newToken;
  try {
    await api(`/api/admin/accounts/${id}`, { method: "PUT", body: JSON.stringify(patch) });
    els.editForm.hidden = true;
    refresh();
  } catch (err) { alert(err.message); }
});

// ─── Auto Token Bot ──────────────────────────────────────────────────────────

// Step keyword map: detects which step is active from log message
const STEP_KEYWORDS = [
  ["Step 1", "iCloud", "email", "Generate"],         // step 1
  ["Step 2", "Figma", "Daftar", "signup"],            // step 2
  ["Step 3", "verif", "inbox", "Refresh inbox"],      // step 3
  ["Step 4", "verif", "link"],                        // step 4
  ["Step 5", "weave", "Bearer", "Capture", "token"],  // step 5
];

function updateStepFromMsg(msg) {
  const lower = msg.toLowerCase();
  for (let i = 0; i < STEP_KEYWORDS.length; i++) {
    const keywords = STEP_KEYWORDS[i];
    if (keywords.some((k) => lower.includes(k.toLowerCase()))) {
      // Mark steps up to i as done, i as active, rest as idle
      for (let j = 1; j <= 5; j++) {
        const el = $(`bstep-${j}`);
        if (!el) continue;
        el.classList.remove("step-active", "step-done", "step-idle");
        if (j < i + 1) el.classList.add("step-done");
        else if (j === i + 1) el.classList.add("step-active");
        else el.classList.add("step-idle");
      }
      break;
    }
  }
}

function resetSteps(state = "idle") {
  for (let i = 1; i <= 5; i++) {
    const el = $(`bstep-${i}`);
    if (!el) continue;
    el.classList.remove("step-active", "step-done", "step-idle");
    if (state === "done") el.classList.add("step-done");
  }
}

function appendLog(msg, type = "info") {
  const body = els.logBody;
  // Remove placeholder
  const placeholder = body.querySelector(".log-info");
  if (placeholder && placeholder.textContent.includes("Menunggu")) placeholder.remove();

  const line = document.createElement("div");
  line.className = `log-line log-${type}`;
  line.textContent = msg;
  body.appendChild(line);
  // Keep max 200 lines
  while (body.children.length > 200) body.removeChild(body.firstChild);
  body.scrollTop = body.scrollHeight;
}

function setBotStatus(status) {
  const badge = els.botStatusBadge;
  badge.className = `badge badge-${status}`;
  const labels = { idle: "IDLE", running: "RUNNING", success: "SUCCESS", error: "ERROR" };
  badge.textContent = labels[status] || status.toUpperCase();
  
  if (status === "running") {
    els.botRunBtn.style.display = "none";
    if (els.botReviveRunBtn) els.botReviveRunBtn.style.display = "none";
    if (els.botStopBtn) els.botStopBtn.style.display = "inline-block";
  } else {
    els.botRunBtn.style.display = "inline-block";
    els.botRunBtn.disabled = false;
    els.botRunBtn.textContent = "▶ Buat Akun Baru Sekarang";
    if (els.botReviveRunBtn) {
      els.botReviveRunBtn.style.display = "inline-block";
      els.botReviveRunBtn.disabled = false;
    }
    if (els.botStopBtn) els.botStopBtn.style.display = "none";
  }
}

function connectSse() {
  closeSse();
  const url = `/api/admin/auto-token/stream`;
  const headers = { "x-admin-password": adminPass };

  // EventSource doesn't support custom headers, use fetch with ReadableStream
  const ctrl = new AbortController();
  sseSource = ctrl;

  fetch(url, { headers, signal: ctrl.signal })
    .then(async (res) => {
      const reader = res.body.getReader();
      const decoder = new TextDecoder();
      let buffer = "";
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buffer += decoder.decode(value, { stream: true });
        const lines = buffer.split("\n");
        buffer = lines.pop();
        for (const line of lines) {
          if (line.startsWith("data: ")) {
            try {
              const event = JSON.parse(line.slice(6));
              handleSseEvent(event);
            } catch {}
          }
        }
      }
    })
    .catch((err) => {
      if (err.name !== "AbortError") {
        appendLog("❌ SSE disconnect: " + err.message, "error");
        // Reconnect after 5s
        setTimeout(() => { if (adminPass) connectSse(); }, 5000);
      }
    });
}

function closeSse() {
  if (sseSource) {
    sseSource.abort?.();
    sseSource = null;
  }
}

function handleSseEvent(event) {
  const { type, msg } = event;

  if (type === "connected") {
    appendLog(msg, "info");
    return;
  }
  if (type === "start") {
    setBotStatus("running");
    resetSteps("idle");
    appendLog(msg, "info");
    return;
  }
  if (type === "success") {
    stopCaptchaAlarm();
    setBotStatus("success");
    resetSteps("done");
    appendLog(msg, "success");
    refresh(); // Reload account list
    updateLastRun("success");
    loadBotStatus(false).catch(() => {});
    return;
  }
  if (type === "error") {
    stopCaptchaAlarm();
    setBotStatus("error");
    appendLog(msg, "error");
    updateLastRun("error");
    loadBotStatus(false).catch(() => {});
    return;
  }
  if (type === "warn") {
    appendLog(msg, "warn");
    return;
  }
  if (type === "captcha") {
    appendLog(msg, "warn");
    triggerCaptchaAlarm();
    return;
  }

  // CAPTCHA selesai diselesaikan manual → hentikan loop alarm
  if (captchaAlarmActive && typeof msg === "string" && /captcha\s+terselesaikan|melanjutkan/i.test(msg)) {
    stopCaptchaAlarm();
  }

  if (typeof msg === "string") {
    const match = msg.match(/✅\s+BERHASIL:\s+([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/);
    if (match) {
      const email = match[1].toLowerCase().trim();
      const textarea = els.bulkEmailInput;
      if (textarea) {
        const lines = textarea.value.split("\n");
        const filtered = lines.filter(line => {
          const trimmed = line.trim();
          if (!trimmed) return true;
          const colonIdx = trimmed.indexOf(":");
          const lineEmail = (colonIdx > 0 ? trimmed.substring(0, colonIdx) : trimmed).trim().toLowerCase();
          return lineEmail !== email;
        });
        textarea.value = filtered.join("\n");
      }
    }
  }

  // Regular info log — also check for step keywords
  appendLog(msg, "info");
  updateStepFromMsg(msg);
}

function updateLastRun(status) {
  const now = new Date().toLocaleString("id-ID");
  els.botLastRun.hidden = false;
  els.botLastRunText.textContent = `${now} · ${status === "success" ? "✅ Berhasil" : "❌ Gagal"}`;
}

// ─── Bot controls ─────────────────────────────────────────────────────────────

els.botRunBtn.addEventListener("click", async () => {
  try {
    setBotStatus("running");
    appendLog("📧 Menghasilkan email baru via ICLOUD...", "info");

    // Step 1: Generate a new email via ICLOUD API
    let email = "";
    try {
      const genRes = await api("/api/admin/icloud/generate", {
        method: "POST",
        body: JSON.stringify({ count: 1 }),
      });
      const emails = genRes.emails || genRes.data || [];
      if (emails.length > 0) {
        email = emails[0].email || emails[0];
      }
    } catch (e) {
      // Fallback: generate random email with timestamp
    }

    if (!email) {
      const ts = Date.now().toString(36);
      email = `user${ts}@tekno-mail.my.id`;
      appendLog(`⚠️ Gagal generate via ICLOUD, pakai fallback: ${email}`, "warn");
    }

    appendLog(`✅ Email: ${email}`, "success");
    appendLog(`🆕 Membuat akun Google baru & login Weavy...`, "info");

    // Step 2: Call create-account endpoint (runs in background — SSE akan update status)
    await api("/api/admin/auto-token/create-account", {
      method: "POST",
      body: JSON.stringify({ email }),
    });

    // Jangan setBotStatus("idle") — SSE event "success"/"error" yang akan mengubah status
    // Stop button tetap muncul selama proses background berjalan
  } catch (err) {
    appendLog(`❌ Gagal memulai pembuatan akun: ${err.message}`, "error");
    setBotStatus("error");
  }
});

if (els.botReviveRunBtn) {
  els.botReviveRunBtn.addEventListener("click", async () => {
    try {
      setBotStatus("running");
      appendLog("▶ Memulai proses revive akun...", "info");
      await api("/api/admin/auto-token/run", { method: "POST", body: JSON.stringify({ force: true, mode: "revive_only" }) });
    } catch (err) {
      appendLog(`❌ Gagal memulai revive: ${err.message}`, "error");
      setBotStatus("error");
    }
  });
}

// ─── Bulk Bot: email list dari textarea ────────────────────────────────────────

let bulkBotActive = false;
let bulkBotEventSource = null;

els.botBulkRunBtn.addEventListener("click", async () => {
  const raw = els.bulkEmailInput.value.trim();
  if (!raw) {
    alert("Masukkan daftar akun terlebih dahulu. Format: email:password per baris.");
    return;
  }

  // Parse email:password pairs
  const accounts = raw
    .split(/\r?\n/)
    .map((l) => l.trim())
    .filter((l) => l && l.includes("@"))
    .map((line) => {
      const colonIdx = line.indexOf(":");
      if (colonIdx > 0) {
        return { email: line.substring(0, colonIdx).trim(), password: line.substring(colonIdx + 1).trim() };
      }
      return { email: line.trim(), password: "" };
    });

  if (!accounts.length) {
    alert("Tidak ada akun valid (harus mengandung @).");
    return;
  }

  try {
    bulkBotActive = true;
    els.botBulkRunBtn.style.display = "none";
    els.botBulkStopBtn.style.display = "";
    els.bulkBotStatus.textContent = `⏳ Memproses ${accounts.length} akun Figma...`;
    setBotStatus("running");
    appendLog(`▶ Memulai Bulk Bot untuk ${accounts.length} akun Figma...`, "info");

    const res = await fetch("/api/admin/auto-token/start-bulk", {
      method: "POST",
      headers: { "Content-Type": "application/json", "x-admin-password": adminPass },
      body: JSON.stringify({ accounts }),
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);

    appendLog(`✅ ${data.msg || "Bulk bot selesai."}`, data.ok ? "success" : "warn");

    if (data.results) {
      for (const r of data.results) {
        appendLog(`  ${r.ok ? "✅" : "❌"} ${r.email}: ${r.ok ? "BERHASIL" : r.error}`, r.ok ? "success" : "error");
      }
    }

    setBotStatus("idle");
    els.bulkBotStatus.textContent = `Selesai: ${data.success || 0} berhasil, ${data.failed || 0} gagal.`;
    refresh();
  } catch (err) {
    appendLog(`❌ Bulk bot error: ${err.message}`, "error");
    setBotStatus("error");
    els.bulkBotStatus.textContent = `Error: ${err.message}`;
  } finally {
    bulkBotActive = false;
    els.botBulkRunBtn.style.display = "";
    els.botBulkStopBtn.style.display = "none";
  }
});

els.botBulkStopBtn.addEventListener("click", async () => {
  try {
    await api("/api/admin/auto-token/stop", { method: "POST" });
    appendLog("⏹️ Permintaan stop bulk bot dikirim.", "warn");
    if (bulkBotEventSource) {
      bulkBotEventSource.close();
      bulkBotEventSource = null;
    }
  } catch (err) {
    appendLog(`❌ Gagal stop: ${err.message}`, "error");
  }
});

els.botStopBtn.addEventListener("click", async () => {
  try {
    stopCaptchaAlarm();
    els.botStopBtn.disabled = true;
    els.botStopBtn.textContent = "⏳ Menghentikan...";
    appendLog("🛑 Mengirim permintaan stop bot...", "warn");
    const res = await api("/api/admin/auto-token/stop", { method: "POST" });
    appendLog(`⏹️ ${res.msg || "Bot dihentikan"}`, "warn");
    setBotStatus("idle");
    // Refresh config — pastikan toggles UI ikut mati
    await loadBotConfig();
  } catch (err) {
    appendLog(`❌ Gagal menghentikan bot: ${err.message}`, "error");
  } finally {
    els.botStopBtn.disabled = false;
    els.botStopBtn.textContent = "⏹️ Hentikan Bot";
  }
});

// ─── Generate Email @tekno-mail.my.id ─────────────────────────────────────

let generatedEmails = [];

async function loadIcloudEmails() {
  try {
    const res = await api("/api/admin/icloud/emails");
    if (res.ok && res.emails) {
      generatedEmails = res.emails;
      renderIcloudEmailList();
    }
  } catch (err) {
    console.error("loadIcloudEmails:", err);
  }
}

function renderIcloudEmailList() {
  if (!generatedEmails.length) {
    els.genEmailList.innerHTML = '<span class="hint">Belum ada email. Klik Generate untuk membuat.</span>';
    els.genEmailUseAllBtn.style.display = "none";
    els.genEmailCountLabel.textContent = "";
    return;
  }

  const now = new Date();
  const items = generatedEmails.map((e) => {
    const expired = e.expiresAt && new Date(e.expiresAt) < now;
    const icon = e.pinned ? "📌" : (expired ? "⏰" : "✅");
    const cls = expired ? "color: #ef4444;" : (e.pinned ? "color: #fbbf24;" : "color: #10b981;");
    const expText = e.expiresAt ? ` · sampai ${new Date(e.expiresAt).toLocaleTimeString("id-ID", { hour: "2-digit", minute: "2-digit" })}` : "";
    return `<div style="${cls} margin-bottom: 2px; cursor: pointer;" title="Klik untuk copy" onclick="navigator.clipboard.writeText('${e.email}').then(()=>this.style.opacity='0.5',()=>{})">${icon} ${e.email}${expText}</div>`;
  });

  els.genEmailList.innerHTML = items.join("");
  els.genEmailUseAllBtn.style.display = "";
  const active = generatedEmails.filter((e) => !e.expiresAt || new Date(e.expiresAt) >= now);
  els.genEmailCountLabel.textContent = `${active.length} aktif dari ${generatedEmails.length} email`;
}

els.genEmailBtn.addEventListener("click", async () => {
  const prefix = els.genEmailPrefix.value.trim();
  const count = parseInt(els.genEmailCount.value) || 1;
  els.genEmailBtn.disabled = true;
  els.genEmailBtn.textContent = "⏳ Generating...";
  els.genEmailResult.textContent = "";

  try {
    const res = await api("/api/admin/icloud/generate", {
      method: "POST",
      body: JSON.stringify({ prefix, count }),
    });
    if (res.ok && res.emails?.length) {
      els.genEmailResult.innerHTML = `<span style="color:#10b981;">✅ ${res.emails.length} email berhasil dibuat!</span>`;
      // Auto-populate bulk email textarea
      const existing = els.bulkEmailInput.value.trim();
      const newEmails = res.emails.join("\n");
      els.bulkEmailInput.value = existing ? existing + "\n" + newEmails : newEmails;
      appendLog(`✉️ ${res.emails.length} email dibuat: ${res.emails.join(", ")}`, "info");
      await loadIcloudEmails();
    } else {
      els.genEmailResult.innerHTML = `<span style="color:#ef4444;">❌ ${res.error || "Gagal generate email"}</span>`;
    }
  } catch (err) {
    els.genEmailResult.innerHTML = `<span style="color:#ef4444;">❌ ${err.message}</span>`;
  } finally {
    els.genEmailBtn.disabled = false;
    els.genEmailBtn.textContent = "➕ Generate";
  }
});

els.genEmailRefreshBtn.addEventListener("click", async () => {
  els.genEmailRefreshBtn.textContent = "⏳ Loading...";
  await loadIcloudEmails();
  els.genEmailRefreshBtn.textContent = "🔄 Refresh List";
});

els.genEmailUseAllBtn.addEventListener("click", () => {
  const now = new Date();
  const active = generatedEmails
    .filter((e) => !e.expiresAt || new Date(e.expiresAt) >= now)
    .map((e) => e.email);
  if (!active.length) {
    appendLog("⚠️ Tidak ada email aktif.", "warn");
    return;
  }
  els.bulkEmailInput.value = active.join("\n");
  appendLog(`📥 ${active.length} email aktif dimasukkan ke Bulk Bot.`, "info");
});

// ─── ICLOUD Inbox Viewer ────────────────────────────────────────────────────

async function loadInboxThreads() {
  try {
    const res = await api("/api/admin/icloud/inbox");
    if (!res.ok || !res.threads?.length) {
      els.inboxList.innerHTML = '<span class="hint">📭 Inbox kosong atau gagal load.</span>';
      return;
    }

    const items = res.threads.map((t, i) => {
      const date = t.date ? new Date(t.date).toLocaleTimeString("id-ID", { hour: "2-digit", minute: "2-digit" }) : "";
      const subj = (t.subject || "(no subject)").substring(0, 50);
      const from = (t.from || "").substring(0, 25);
      const badge = (t.text || "").toLowerCase().includes("verification") ? " 🔑" : "";
      return `<div style="padding:4px 0; border-bottom:1px solid rgba(255,255,255,0.05); cursor:pointer;" 
            onclick="this.style.background='rgba(59,130,246,0.1)'; loadInboxThreadDetail('${t.id}')">
        <span style="color:#6b7280;">${date}</span>
        <span style="color:#93c5fd;">${from}</span>
        <span>${subj}${badge}</span>
      </div>`;
    });

    els.inboxList.innerHTML = items.join("");
  } catch (err) {
    els.inboxList.innerHTML = `<span style="color:#ef4444;">❌ ${err.message}</span>`;
  }
}

async function loadInboxThreadDetail(threadId) {
  try {
    els.inboxDetail.style.display = "block";
    els.inboxDetail.textContent = "⏳ Loading...";
    const res = await api("/api/admin/icloud/inbox/thread", {
      method: "POST",
      body: JSON.stringify({ threadId }),
    });
    if (res.ok && res.messages?.length) {
      // Render HTML as real preview (innerHTML), with From header
      const parts = res.messages.map((m) => {
        const from = m.from ? `<div style="color:#93c5fd; font-size:0.7rem; margin-bottom:6px; padding-bottom:4px; border-bottom:1px solid rgba(255,255,255,0.06);">From: ${m.from}</div>` : "";
        const body = m.html || m.text || m.body || "";
        return `<div style="margin-bottom:12px;">${from}${body}</div>`;
      });
      els.inboxDetail.innerHTML = parts.join("");
    } else {
      els.inboxDetail.textContent = res.error || "Gagal load thread.";
    }
  } catch (err) {
    els.inboxDetail.textContent = `❌ ${err.message}`;
  }
}

// Expose to global scope for onclick
window.loadInboxThreadDetail = loadInboxThreadDetail;

els.inboxRefreshBtn.addEventListener("click", async () => {
  els.inboxRefreshBtn.textContent = "⏳ Loading...";
  await loadInboxThreads();
  els.inboxRefreshBtn.textContent = "🔄 Refresh";
});

// Auto-load on tab switch
const origToolsClick = els.tabBtnTools?.onclick;
if (els.tabBtnTools) {
  els.tabBtnTools.addEventListener("click", () => {
    // no-op — ICLOUD load moved to dedicated tab
  });
}

// ─── ICLOUD Account Management ─────────────────────────────────────────────

let icloudAccountsList = [];

async function loadIcloudAccounts() {
  try {
    const res = await api("/api/admin/icloud/accounts");
    if (res.ok && res.accounts) {
      icloudAccountsList = res.accounts;
      renderIcloudAccountList();
    }
  } catch (err) {
    console.error("loadIcloudAccounts:", err);
  }
}

function renderIcloudAccountList() {
  const list = els.icloudAccountList;
  if (!list) return;
  if (!icloudAccountsList.length) {
    list.innerHTML = '<span style="font-size: 0.75rem; color: var(--muted); text-align: center; padding: 12px 0; display: block;">Belum ada akun</span>';
    return;
  }
  list.innerHTML = icloudAccountsList.map(a => {
    const sel = els.icloudAccountId.value === a.id ? 'background: rgba(168,85,247,0.2); border-color: var(--primary);' : '';
    return `<div data-icloud-id="${a.id}" class="icloud-account-item" style="padding: 8px; border: 1px solid var(--border); border-radius: 6px; cursor: pointer; transition: all 0.2s; ${sel}">
      <div style="font-size: 0.78rem; font-weight: 600; color: #e2e2e2;">${escapeHtml(a.name || "Tanpa Nama")}</div>
      <div style="font-size: 0.65rem; color: var(--muted);">DSID: ${a.dsid || "-"}</div>
      <div style="font-size: 0.65rem; color: var(--muted);">${a.hasCookies ? "✅ Cookies" : "⚠️ No Cookies"} | ${a.hasAppPassword ? "✅ IMAP" : "⚠️ No IMAP"}</div>
    </div>`;
  }).join("");

  // Click handlers
  list.querySelectorAll(".icloud-account-item").forEach(el => {
    el.addEventListener("click", () => selectIcloudAccount(el.dataset.icloudId));
  });
}

async function selectIcloudAccount(id) {
  try {
    const res = await api(`/api/admin/icloud/accounts/${id}`);
    if (res.ok && res.account) {
      fillIcloudForm(res.account);
      renderIcloudAccountList();
      els.icloudAccountDeleteBtn.style.display = "inline-block";
    }
  } catch (err) {
    console.error("selectIcloudAccount:", err);
  }
}

function fillIcloudForm(acc) {
  els.icloudAccountId.value = acc.id || "";
  els.icloudAccName.value = acc.name || "";
  els.icloudAccDsid.value = acc.dsid || "";
  els.icloudAccClientId.value = acc.clientId || "";
  els.icloudAccCookies.value = acc.cookies || "";
  els.icloudAccEmail.value = acc.email || "";
  els.icloudAccAppPassword.value = acc.appPassword || "";
  els.icloudAccSubdomain.value = acc.subdomain || "";
}

function clearIcloudForm() {
  els.icloudAccountId.value = "";
  els.icloudAccName.value = "";
  els.icloudAccDsid.value = "";
  els.icloudAccClientId.value = "";
  els.icloudAccCookies.value = "";
  els.icloudAccEmail.value = "";
  els.icloudAccAppPassword.value = "";
  els.icloudAccSubdomain.value = "";
  els.icloudAccountDeleteBtn.style.display = "none";
  renderIcloudAccountList();
}

// Test connection
async function testIcloudConnection() {
  const badge = els.icloudStatusBadge;
  if (!badge) return;
  badge.textContent = "⏳ Mengecek...";
  badge.style.background = "#1a1a2e";
  badge.style.color = "#fbbf24";
  try {
    const res = await api("/api/admin/icloud/test-connection");
    if (res.ok) {
      badge.textContent = "🟢 Koneksi OK";
      badge.style.background = "rgba(52,211,153,0.15)";
      badge.style.color = "#34d399";
    } else {
      badge.textContent = "🔴 " + (res.error || "Gagal Koneksi");
      badge.style.background = "rgba(239,68,68,0.15)";
      badge.style.color = "#ef4444";
    }
  } catch (err) {
    badge.textContent = "🔴 " + (err.message || "Gagal cek");
    badge.style.background = "rgba(239,68,68,0.15)";
    badge.style.color = "#ef4444";
  }
}

// Save account
if (els.icloudAccountSaveBtn) {
  els.icloudAccountSaveBtn.addEventListener("click", async () => {
    els.icloudAccountSaveBtn.textContent = "⏳ Menyimpan...";
    els.icloudAccountSaveBtn.disabled = true;
    els.icloudSettingsMsg.innerHTML = "";
    try {
      let payload;
      // JSON mode — parse from textarea
      if (els.icloudJsonMode && els.icloudJsonMode.style.display !== "none") {
        const raw = els.icloudAccJson.value.trim();
        if (!raw) throw new Error("JSON kosong");
        const parsed = JSON.parse(raw);
        // Deteksi full file format { "accounts": [...] }
        if (parsed.accounts && Array.isArray(parsed.accounts)) {
          // Batch import — simpan semua akun sekaligus
          let ok = 0, fail = 0;
          for (const acc of parsed.accounts) {
            try {
              const r = await api("/api/admin/icloud/accounts", {
                method: "POST",
                body: JSON.stringify(acc),
              });
              if (r.ok) ok++; else fail++;
            } catch { fail++; }
          }
          els.icloudSettingsMsg.innerHTML = `<span style="color:#34d399;">✅ Batch import: ${ok} berhasil, ${fail} gagal</span>`;
          await loadIcloudAccounts();
          await testIcloudConnection();
          els.icloudAccountSaveBtn.textContent = "💾 Simpan";
          els.icloudAccountSaveBtn.disabled = false;
          return;
        }
        payload = parsed;
      } else {
        payload = {
          id: els.icloudAccountId.value || undefined,
          name: els.icloudAccName.value.trim(),
          dsid: els.icloudAccDsid.value.trim(),
          clientId: els.icloudAccClientId.value.trim(),
          cookies: els.icloudAccCookies.value.trim(),
          email: els.icloudAccEmail.value.trim(),
          appPassword: els.icloudAccAppPassword.value.trim(),
          subdomain: els.icloudAccSubdomain.value.trim(),
        };
      }
      const res = await api("/api/admin/icloud/accounts", {
        method: "POST",
        body: JSON.stringify(payload),
      });
      if (res.ok) {
        els.icloudSettingsMsg.innerHTML = '<span style="color:#34d399;">✅ Akun iCloud berhasil disimpan!</span>';
        await loadIcloudAccounts();
        if (res.account) {
          els.icloudAccountId.value = res.account.id;
          els.icloudAccountDeleteBtn.style.display = "inline-block";
        }
        await testIcloudConnection();
      } else {
        els.icloudSettingsMsg.innerHTML = `<span style="color:#ef4444;">❌ ${res.error || "Gagal menyimpan"}</span>`;
      }
    } catch (err) {
      els.icloudSettingsMsg.innerHTML = `<span style="color:#ef4444;">❌ ${err.message}</span>`;
    }
    els.icloudAccountSaveBtn.textContent = "💾 Simpan";
    els.icloudAccountSaveBtn.disabled = false;
  });
}

// JSON toggle — switch between Form and JSON input
if (els.icloudJsonToggleBtn) {
  let jsonMode = false;
  els.icloudJsonToggleBtn.addEventListener("click", () => {
    jsonMode = !jsonMode;
    if (jsonMode) {
      els.icloudFormMode.style.display = "none";
      els.icloudJsonMode.style.display = "flex";
      els.icloudJsonToggleBtn.textContent = "Form";
      els.icloudJsonToggleBtn.style.background = "rgba(168,85,247,0.2)";
      els.icloudJsonToggleBtn.style.color = "var(--primary)";
      // Fill JSON from current form values
      const current = {
        id: els.icloudAccountId.value || undefined,
        name: els.icloudAccName.value.trim() || undefined,
        subdomain: els.icloudAccSubdomain.value.trim() || "p188-maildomainws.icloud.com",
        dsid: els.icloudAccDsid.value.trim() || undefined,
        clientId: els.icloudAccClientId.value.trim() || undefined,
        cookies: els.icloudAccCookies.value.trim() || undefined,
        email: els.icloudAccEmail.value.trim() || undefined,
        appPassword: els.icloudAccAppPassword.value.trim() || undefined,
      };
      if (!current.id) delete current.id;
      els.icloudAccJson.value = JSON.stringify(current, null, 2);
      els.icloudAccountDeleteBtn.style.display = "none";
    } else {
      els.icloudFormMode.style.display = "flex";
      els.icloudJsonMode.style.display = "none";
      els.icloudJsonToggleBtn.textContent = "JSON";
      els.icloudJsonToggleBtn.style.background = "#1a1a2e";
      els.icloudJsonToggleBtn.style.color = "var(--muted)";
    }
    els.icloudAccountId.value = "";
  });
}

// Delete account
if (els.icloudAccountDeleteBtn) {
  els.icloudAccountDeleteBtn.addEventListener("click", async () => {
    const id = els.icloudAccountId.value;
    if (!id) return;
    if (!confirm("Hapus akun iCloud ini? Tindakan ini tidak dapat dibatalkan.")) return;
    try {
      const res = await api(`/api/admin/icloud/accounts/${id}`, { method: "DELETE" });
      if (res.ok) {
        els.icloudSettingsMsg.innerHTML = '<span style="color:#34d399;">🗑 Akun iCloud dihapus.</span>';
        clearIcloudForm();
        await loadIcloudAccounts();
        await testIcloudConnection();
      } else {
        els.icloudSettingsMsg.innerHTML = `<span style="color:#ef4444;">❌ ${res.error || "Gagal menghapus"}</span>`;
      }
    } catch (err) {
      els.icloudSettingsMsg.innerHTML = `<span style="color:#ef4444;">❌ ${err.message}</span>`;
    }
  });
}

// New button
if (els.icloudAccountNewBtn) {
  els.icloudAccountNewBtn.addEventListener("click", clearIcloudForm);
}

// Clear button
if (els.icloudAccountClearBtn) {
  els.icloudAccountClearBtn.addEventListener("click", clearIcloudForm);
}

// Test button
if (els.icloudTestBtn) {
  els.icloudTestBtn.addEventListener("click", testIcloudConnection);
}

// Load on init
loadIcloudAccounts().then(() => testIcloudConnection());

els.logClearBtn.addEventListener("click", () => {
  els.logBody.innerHTML = `<div class="log-line log-info">● Log dibersihkan.</div>`;
});

async function saveSchedulerConfig(payload) {
  try {
    const res = await api("/api/admin/auto-token/config", {
      method: "POST",
      body: JSON.stringify(payload),
    });
    appendLog(`⏰ Scheduler: ${res.msg}`, "info");
    await loadBotStatus(false);
    return res;
  } catch (err) {
    appendLog(`❌ Scheduler error: ${err.message}`, "error");
    throw err;
  }
}

els.creatorSchedulerInterval.addEventListener("change", () => {
  els.creatorSchedulerIntervalCustom.style.display = els.creatorSchedulerInterval.value === "custom" ? "inline-block" : "none";
});

els.creatorSchedulerSaveBtn.addEventListener("click", async () => {
  try {
    const mins = getCreatorSchedulerIntervalMinutes();
    await saveSchedulerConfig({ creatorIntervalMinutes: mins });
  } catch (err) {
    alert(err.message);
  }
});

els.creatorSchedulerToggle.addEventListener("change", async () => {
  const enabled = els.creatorSchedulerToggle.checked;
  try {
    const mins = getCreatorSchedulerIntervalMinutes();
    await saveSchedulerConfig({ creatorEnabled: enabled, creatorIntervalMinutes: mins });
  } catch (err) {
    els.creatorSchedulerToggle.checked = !enabled;
  }
});

els.reviveSchedulerInterval.addEventListener("change", () => {
  els.reviveSchedulerIntervalCustom.style.display = els.reviveSchedulerInterval.value === "custom" ? "inline-block" : "none";
});

els.reviveSchedulerSaveBtn.addEventListener("click", async () => {
  try {
    const mins = getReviveSchedulerIntervalMinutes();
    await saveSchedulerConfig({ reviveIntervalMinutes: mins });
  } catch (err) {
    alert(err.message);
  }
});

els.reviveSchedulerToggle.addEventListener("change", async () => {
  const enabled = els.reviveSchedulerToggle.checked;
  try {
    const mins = getReviveSchedulerIntervalMinutes();
    await saveSchedulerConfig({ reviveEnabled: enabled, reviveIntervalMinutes: mins });
  } catch (err) {
    els.reviveSchedulerToggle.checked = !enabled;
  }
});

// Headless toggle
els.headlessToggle.addEventListener("change", async () => {
  const headless = els.headlessToggle.checked;
  try {
    const res = await api("/api/admin/auto-token/config", {
      method: "POST",
      body: JSON.stringify({ headless }),
    });
    appendLog(`⚙️ Mode Browser: ${headless ? "Sembunyikan" : "Tampilkan"} (Headless: ${headless})`, "info");
  } catch (err) {
    appendLog(`❌ Gagal mengubah mode browser: ${err.message}`, "error");
    els.headlessToggle.checked = !headless; // revert
  }
});

els.schedulerTestBtn.addEventListener("click", async () => {
  const delaySeconds = Number(els.schedulerTestSeconds.value || 15);
  if (!Number.isFinite(delaySeconds) || delaySeconds < 5 || delaySeconds > 300) {
    alert("Delay test harus antara 5 sampai 300 detik.");
    return;
  }

  try {
    const res = await api("/api/admin/auto-token/test", {
      method: "POST",
      body: JSON.stringify({ delaySeconds }),
    });
    appendLog(`🧪 ${res.msg}`, "info");
    await loadBotStatus(false);
  } catch (err) {
    appendLog(`❌ Gagal menjadwalkan test: ${err.message}`, "error");
  }
});

function startCreatorCountdown() {
  stopCreatorCountdown();
  creatorCountdownInterval = setInterval(() => {
    if (!creatorNextRunTime) return;
    const diff = Math.max(0, creatorNextRunTime - Date.now());
    els.creatorCountdownTimer.textContent = formatCountdown(diff);
    if (diff === 0) {
      creatorNextRunTime = null;
      loadBotStatus(false).catch(() => {});
    }
  }, 1000);
}

function stopCreatorCountdown() {
  if (creatorCountdownInterval) { clearInterval(creatorCountdownInterval); creatorCountdownInterval = null; }
}

function startReviveCountdown() {
  stopReviveCountdown();
  reviveCountdownInterval = setInterval(() => {
    if (!reviveNextRunTime) return;
    const diff = Math.max(0, reviveNextRunTime - Date.now());
    els.reviveCountdownTimer.textContent = formatCountdown(diff);
    if (diff === 0) {
      reviveNextRunTime = null;
      loadBotStatus(false).catch(() => {});
    }
  }, 1000);
}

function stopReviveCountdown() {
  if (reviveCountdownInterval) { clearInterval(reviveCountdownInterval); reviveCountdownInterval = null; }
}

async function loadBotStatus(updateStatusBadge = true) {
  try {
    const st = await api("/api/admin/auto-token/status");
    
    // Sync Creator scheduler UI
    els.creatorSchedulerToggle.checked = st.creatorActive;
    syncCreatorIntervalControls(st.creatorIntervalMinutes || 45);
    if (st.creatorActive && st.creatorNextRunAt) {
      creatorNextRunTime = new Date(st.creatorNextRunAt).getTime();
      startCreatorCountdown();
      els.creatorCountdown.hidden = false;
    } else {
      creatorNextRunTime = null;
      stopCreatorCountdown();
      els.creatorCountdown.hidden = true;
    }

    // Sync Revive scheduler UI
    els.reviveSchedulerToggle.checked = st.reviveActive;
    syncReviveIntervalControls(st.reviveIntervalMinutes || 15);
    if (st.reviveActive && st.reviveNextRunAt) {
      reviveNextRunTime = new Date(st.reviveNextRunAt).getTime();
      startReviveCountdown();
      els.reviveCountdown.hidden = false;
    } else {
      reviveNextRunTime = null;
      stopReviveCountdown();
      els.reviveCountdown.hidden = true;
    }

    els.headlessToggle.checked = st.headless;
    
    if (updateStatusBadge) {
      if (st.running) setBotStatus("running");
      else if (!st.lastRunResult) setBotStatus("idle");
    } else if (st.running) {
      setBotStatus("running");
    }
    if (st.lastRunAt) {
      const status = st.lastRunResult?.ok ? "success" : "error";
      updateLastRun(status);
    }
  } catch {}
}

// ─── Voucher management ──────────────────────────────────────────────────────

let _allVouchersCache = [];

async function refreshVouchers() {
  const { vouchers } = await api("/api/admin/vouchers");
  _allVouchersCache = vouchers;
  // Urutkan: terbaru di atas
  _allVouchersCache.sort((a, b) => new Date(b.addedAt || 0).getTime() - new Date(a.addedAt || 0).getTime());
  populateVoucherCreatorFilter();
  applyVoucherFilters();
  refreshVoucherStats().catch(() => {});

  // Update heading di tab Voucher
  const headingEl = document.querySelector("#tab-panel-voucher h3");
  if (headingEl) {
    if (adminRole === "mitra") {
      headingEl.textContent = `📋 Daftar Member Anda (${_allVouchersCache.length})`;
    } else {
      headingEl.textContent = "Daftar Member / Voucher Aktif";
    }
  }
}

async function refreshVoucherStats() {
  const stats = await api("/api/admin/vouchers/stats");
  const isMitra = (adminRole === "mitra");
  const isOwner = (adminRole === "owner");
  const elT = $("vch-stat-total");
  const elA = $("vch-stat-active");
  const elE = $("vch-stat-expired");
  const elT2 = $("vch-stat-tiers");
  const elTL = document.querySelector("#vch-stat-total")?.previousElementSibling;

  if (elT) elT.textContent = stats.total;
  if (elA) elA.textContent = stats.active;
  if (elE) elE.textContent = stats.expired;
  if (elT2) elT2.textContent = `${stats.pro} / ${stats.vip}`;

  // Ubah label sesuai role
  if (elTL) {
    if (isMitra) elTL.textContent = "👤 MEMBER SAYA";
    else if (isOwner) elTL.textContent = "👥 TOTAL MEMBER";
    else elTL.textContent = "👥 MEMBER SERVER";
  }

  // Per-creator breakdown (only for owner/kasir; mitra sees only themselves)
  const byCreator = $("vch-by-creator");
  const detailsEl = $("vch-by-creator-details");
  if (!byCreator || !detailsEl) return;

  if (isMitra) {
    detailsEl.style.display = "none";
    return;
  }
  detailsEl.style.display = "";

  const entries = Object.entries(stats.byCreator || {})
    .sort((a, b) => b[1].total - a[1].total);
  if (entries.length === 0) {
    byCreator.innerHTML = `<div style="opacity:0.7;">Belum ada data kreator</div>`;
    return;
  }
  byCreator.innerHTML = entries.map(([id, s]) => {
    const isMitra = id.startsWith("mitra_");
    return `
      <div style="display: flex; justify-content: space-between; align-items: center; padding: 6px 0; border-bottom: 1px solid var(--border);">
        <div>
          <strong>${isMitra ? "🤝 " : ""}${s.name}</strong>
          <div style="opacity: 0.6; font-size: 0.7rem;">${id}</div>
        </div>
        <div style="text-align: right;">
          <span style="font-weight: 700;">${s.total}</span> total
          <div style="font-size: 0.7rem; opacity: 0.7;">
            ✅ ${s.active} &nbsp; ⏳ ${s.expired} &nbsp; Pro ${s.pro} &nbsp; VIP ${s.vip}
          </div>
        </div>
      </div>
    `;
  }).join("");
}

function populateVoucherCreatorFilter() {
  const sel = $("vch-search-creator");
  if (!sel) return;
  const current = sel.value;
  const creators = new Set();
  for (const v of _allVouchersCache) {
    if (v.createdBy) creators.add(`${v.createdBy}::${v.createdByName || v.createdBy}`);
  }
  sel.innerHTML = `<option value="">Semua</option>`;
  for (const c of creators) {
    const [id, name] = c.split("::");
    const opt = document.createElement("option");
    opt.value = id;
    opt.textContent = name;
    sel.appendChild(opt);
  }
  sel.value = current;
}

function applyVoucherFilters() {
  const codeQ = ($("vch-search-code")?.value || "").trim().toUpperCase();
  const waQ = ($("vch-search-whatsapp")?.value || "").replace(/[^\d]/g, "");
  const tierQ = $("vch-search-tier")?.value || "";
  const expiryQ = $("vch-search-expiry")?.value || "";
  const creatorQ = $("vch-search-creator")?.value || "";

  const now = Date.now() / 1000;
  const filtered = _allVouchersCache.filter(v => {
    if (codeQ && !(v.code || "").toUpperCase().includes(codeQ)) return false;
    if (waQ) {
      const vWa = (v.whatsapp || "").replace(/[^\d]/g, "");
      if (!vWa.includes(waQ)) return false;
    }
    if (tierQ && v.tier !== tierQ) return false;
    if (expiryQ) {
      const isExpired = v.expiresAt && new Date(v.expiresAt).getTime() < Date.now();
      if (expiryQ === "active" && isExpired) return false;
      if (expiryQ === "expired" && !isExpired) return false;
    }
    if (creatorQ && v.createdBy !== creatorQ) return false;
    return true;
  });

  const summary = $("vch-search-summary");
  if (summary) {
    summary.textContent = `Menampilkan ${filtered.length} dari ${_allVouchersCache.length} voucher`;
  }
  renderVouchers(filtered);
}

// Toggle custom duration days display
els.vchDuration.addEventListener("change", () => {
  const isCustom = els.vchDuration.value === "custom";
  els.vchDurationDaysWrapper.style.display = isCustom ? "flex" : "none";
});

els.vchTier.addEventListener("change", () => {
  els.vchDailyLimit.value = els.vchTier.value === "vip" ? "8" : "5";
});

function renderVouchers(vouchers) {
  if (!vouchers.length) {
    els.voucherList.innerHTML = `<div class="empty-accounts">Belum ada kode voucher VIP. Buat di atas.</div>`;
    return;
  }
  els.voucherList.innerHTML = "";
  const todayStr = new Date().toISOString().split("T")[0];

  for (const v of vouchers) {
    const row = document.createElement("div");
    row.className = "account-row";
    row.style.gridTemplateColumns = "1fr auto";

    const usageToday = v.usage?.[todayStr] || 0;
    const dailyLimit = v.dailyLimit || 3;
    const whatsapp = v.whatsapp || "";
    const tier = v.tier || "standard";
    
    let expTime = null;
    let timeLeftStr = "no exp";
    let isExpired = false;
    let expiresAtStr = "Selamanya";
    let expiresAtDateVal = "";
    
    if (v.expiresAt) {
      expTime = new Date(v.expiresAt).getTime() / 1000;
      timeLeftStr = formatTimeLeft(expTime);
      isExpired = expTime < Date.now() / 1000;
      expiresAtStr = new Date(v.expiresAt).toLocaleDateString('id-ID');
      expiresAtDateVal = v.expiresAt.split('T')[0];
    }

    let priceMetaStr = "";
    if (adminRole === "owner" || adminRole === "kasir") {
      if (v.pricePaid) {
        priceMetaStr += `<span class="dot">·</span> <span>Bayar: <strong>Rp ${v.pricePaid.toLocaleString('id-ID')}</strong></span>`;
      }
      if (v.resellerCost) {
        priceMetaStr += ` <span style="font-size: 0.8rem; color: var(--muted);">(Modal: Rp ${v.resellerCost.toLocaleString('id-ID')} · Komisi: Rp ${v.commission.toLocaleString('id-ID')})</span>`;
      }
    } else if (adminRole === "mitra") {
      if (v.pricePaid) {
        priceMetaStr += `<span class="dot">·</span> <span>Jual (SRP): <strong>Rp ${v.pricePaid.toLocaleString('id-ID')}</strong></span>`;
      }
      if (v.resellerCost) {
        priceMetaStr += `<span class="dot">·</span> <span>Modal: <strong>Rp ${v.resellerCost.toLocaleString('id-ID')}</strong></span>`;
      }
      if (v.commission !== undefined) {
        priceMetaStr += `<span class="dot">·</span> <span style="color: #34d399;">Komisi: <strong>Rp ${v.commission.toLocaleString('id-ID')}</strong></span>`;
      }
    }

    // Trial badge
    const trialBadge = v.isTrial ? `<span class="badge" style="animation: none; background: #6366f1; color: #c7d2fe;">🧪 TRIAL</span>` : "";
    // Trial name display
    const trialNameDisplay = v.isTrial && v.trialName ? `<span style="font-size: 0.78rem; color: #a5b4fc; margin-left: 4px;">— ${escapeHtml(v.trialName)}</span>` : "";

    row.innerHTML = `
      <div class="acc-info">
        <div class="acc-label" style="display: flex; align-items: center; gap: 8px;">
          <span>${escapeHtml(v.code)}</span>
          <span class="badge ${tier === 'vip' ? 'badge-vip' : (tier === 'pro' ? 'badge-running' : 'badge-idle')}" style="animation: none;">${tier.toUpperCase()}</span>
          ${trialBadge}
          ${trialNameDisplay}
        </div>
        <div class="acc-meta" style="margin-top: 4px;">
          <span>WA: <strong>${escapeHtml(whatsapp || '-')}</strong></span>
          <span class="dot">·</span>
          <span>Generate: <strong>${usageToday}/${dailyLimit}</strong></span>
          <span class="dot">·</span>
          <span class="${isExpired ? 'exp-bad' : 'exp-ok'}">Aktif S/D: ${expiresAtStr}</span>
          ${v.isTrial ? '<span class="dot">·</span> <span style="color: #a5b4fc;">Durasi: 1 Hari</span>' : ''}
          ${priceMetaStr}
        </div>
      </div>
      <div class="acc-actions">
        <button type="button" class="ghost small" onclick="openEditVoucher('${escapeHtml(v.code)}', '${escapeHtml(whatsapp)}', '${escapeHtml(tier)}', ${dailyLimit}, '${expiresAtDateVal}')">✏️</button>
        <button type="button" class="ghost small danger" onclick="deleteVoucher('${escapeHtml(v.code)}')">✕ Hapus</button>
      </div>
    `;
    els.voucherList.appendChild(row);
  }
}

els.createVchBtn.addEventListener("click", async () => {
  const code = els.vchCode.value.trim().toUpperCase();
  const tier = els.vchTier.value;
  const whatsapp = els.vchWhatsapp.value.trim();
  const duration = els.vchDuration.value;
  const durationDays = parseInt(els.vchDurationDays.value, 10);
  const dailyLimit = parseInt(els.vchDailyLimit.value, 10);

  if (!code && !whatsapp) {
    return showToast("Silakan masukkan Kode Voucher ATAU Nomor Whatsapp Member!", "warn");
  }

  try {
    const resData = await api("/api/admin/vouchers", {
      method: "POST",
      body: JSON.stringify({ code, tier, whatsapp, duration, durationDays, dailyLimit }),
    });
    // Reset form
    els.vchCode.value = "";
    els.vchWhatsapp.value = "";
    els.vchDuration.value = "1bulan";
    els.vchDurationDays.value = "30";
    els.vchDurationDaysWrapper.style.display = "none";
    els.vchDailyLimit.value = els.vchTier.value === "vip" ? "8" : "5";

    // Dynamic balance and commission update
    if (resData.updatedReseller) {
      resellerBalanceNum = resData.updatedReseller.balance;
      resellerCommissionNum = resData.updatedReseller.totalCommission;
      resellerQuotaNum = resData.updatedReseller.quota;
      sessionStorage.setItem("weavy_reseller_balance", String(resellerBalanceNum));
      sessionStorage.setItem("weavy_reseller_commission", String(resellerCommissionNum));
      sessionStorage.setItem("weavy_reseller_quota", String(resellerQuotaNum));
      applyRoleVisibility();
      
      // Debt warning notification
      if (resData.updatedReseller.isDebt) {
        const debtAmt = resData.updatedReseller.debtAmount;
        const debtMax = resData.updatedReseller.debtLimit;
        if (resData.updatedReseller.debtWarning) {
          showToast(`⚠️ PERINGATAN: Saldo minus Rp ${debtAmt.toLocaleString('id-ID')} — hampir mencapai batas utang Rp ${debtMax.toLocaleString('id-ID')}! Segera lunasi untuk melanjutkan transaksi.`, "warn", 8000);
        } else {
          showToast(`⚠️ Transaksi menggunakan utang: Rp ${debtAmt.toLocaleString('id-ID')} (Batas: Rp ${debtMax.toLocaleString('id-ID')}). Saldo sekarang: Rp ${resellerBalanceNum.toLocaleString('id-ID')}`, "warn", 5000);
        }
      }
    }

    showToast(`Voucher ${tier === "vip" ? "VIP" : "Pro"} berhasil dibuat!`, "success");
    refreshVouchers().catch(() => {});
    // Mitra: langsung pindah ke tab Manajemen Voucher supaya lihat hasilnya
    if (adminRole === "mitra") {
      switchAdminTab("voucher");
    }
  } catch (err) {
    showToast(err.message, "error");
  }
});

// ═══ Trial Voucher System ═══

// Load kuota trial dari server
async function loadTrialQuota() {
  try {
    const res = await api("/api/admin/trial-quota");
    if (res.ok && els.trialQuotaRemaining) {
      els.trialQuotaRemaining.textContent = res.remainingQuota;
      // Disable buttons if quota habis
      const disabled = res.remainingQuota <= 0;
      if (els.trialAutoBtn) els.trialAutoBtn.disabled = disabled;
      if (els.trialCustomBtn) els.trialCustomBtn.disabled = disabled;
      if (els.trialQuotaRemaining) {
        els.trialQuotaRemaining.style.color = disabled ? "#f87171" : "#a5b4fc";
      }
    }
  } catch {}
}

// Buat trial voucher (auto / custom)
async function createTrialVoucher(customName = null) {
  try {
    const btn = customName ? els.trialCustomBtn : els.trialAutoBtn;
    if (btn) { btn.disabled = true; btn.textContent = "⏳ Memproses..."; }

    const res = await api("/api/admin/trial-voucher", {
      method: "POST",
      body: JSON.stringify({ customName }),
    });

    if (res.ok) {
      const v = res.voucher;
      const msgEl = els.trialResultMsg;
      if (msgEl) {
        msgEl.style.display = "block";
        msgEl.style.color = "#6ee7b7";
        msgEl.innerHTML = `✅ Trial berhasil! Kode: <strong>${escapeHtml(v.code)}</strong> — "${escapeHtml(v.trialName)}" · Berlaku 1 hari · Kuota tersisa: <strong>${res.remainingQuota}/5</strong>`;
      }
      showToast(`Trial voucher "${v.trialName}" (${v.code}) berhasil dibuat!`, "success");
      await loadTrialQuota();
      refreshVouchers().catch(() => {});
      refreshVoucherStats().catch(() => {});
    }
  } catch (err) {
    showToast(err.message, "error");
  } finally {
    if (els.trialAutoBtn) { els.trialAutoBtn.disabled = false; els.trialAutoBtn.textContent = "⚡ Buat Trial Otomatis"; }
    if (els.trialCustomBtn) { els.trialCustomBtn.disabled = false; els.trialCustomBtn.textContent = "✏️ Buat Trial Kustom"; }
  }
}

// Event: Buat Trial Otomatis
if (els.trialAutoBtn) {
  els.trialAutoBtn.addEventListener("click", () => createTrialVoucher(null));
}

// Event: Buat Trial Kustom — tampilkan input inline
if (els.trialCustomBtn) {
  els.trialCustomBtn.addEventListener("click", () => {
    const btnRow = document.getElementById("trial-buttons-row");
    const inputRow = document.getElementById("trial-custom-input-row");
    const input = document.getElementById("trial-custom-name-input");
    if (btnRow) btnRow.style.display = "none";
    if (inputRow) inputRow.style.display = "flex";
    if (input) {
      input.value = `Trial ${new Date().toLocaleDateString('id-ID')}`;
      input.focus();
    }
  });
}

// Event: Konfirmasi input kustom
const trialCustomConfirmBtn = document.getElementById("trial-custom-confirm-btn");
if (trialCustomConfirmBtn) {
  trialCustomConfirmBtn.addEventListener("click", async () => {
    const input = document.getElementById("trial-custom-name-input");
    const name = input ? input.value.trim() : "";
    if (!name) {
      showToast("Nama trial tidak boleh kosong.", "warn");
      return;
    }
    // Sembunyikan input, tampilkan tombol
    const btnRow = document.getElementById("trial-buttons-row");
    const inputRow = document.getElementById("trial-custom-input-row");
    if (btnRow) btnRow.style.display = "flex";
    if (inputRow) inputRow.style.display = "none";
    await createTrialVoucher(name);
  });
}

// Event: Batal input kustom
const trialCustomCancelBtn = document.getElementById("trial-custom-cancel-btn");
if (trialCustomCancelBtn) {
  trialCustomCancelBtn.addEventListener("click", () => {
    const btnRow = document.getElementById("trial-buttons-row");
    const inputRow = document.getElementById("trial-custom-input-row");
    if (btnRow) btnRow.style.display = "flex";
    if (inputRow) inputRow.style.display = "none";
  });
}

// Load quota saat tab voucher dibuka
const origSwitchAdminTab = switchAdminTab;
switchAdminTab = function(tabId) {
  origSwitchAdminTab(tabId);
  if (tabId === "voucher") {
    loadTrialQuota().catch(() => {});
  }
};

window.deleteVoucher = async function(code) {
  const confirmed = await showConfirm(`Hapus voucher ${code}?`);
  if (!confirmed) return;

  // Minta password login untuk konfirmasi
  const password = await showPasswordPrompt();
  if (!password) return;

  // Optimistic delete: langsung hapus dari list tanpa nunggu server
  _allVouchersCache = _allVouchersCache.filter(v => v.code !== code);
  applyVoucherFilters();
  refreshVoucherStats().catch(() => {});

  try {
    await api(`/api/admin/vouchers/${encodeURIComponent(code)}`, {
      method: "DELETE",
      headers: { "x-delete-password": password }
    });
    showToast("Voucher berhasil dihapus!", "success");
  } catch (err) {
    const msg = err.message || "";
    if (msg.includes("Password") || msg.includes("password") || msg.includes("salah")) {
      // Password salah, kembalikan data
      showToast("Password salah! Voucher tidak jadi dihapus.", "error");
      refreshVouchers().catch(() => {});
    } else if (msg.includes("404") || msg.includes("Not found") || msg.includes("not found") || msg.includes("403")) {
      showToast("Voucher berhasil dihapus!", "success");
    } else {
      showToast(err.message, "error");
      refreshVouchers().catch(() => {});
    }
  }
};

window.openEditVoucher = function(code, whatsapp, tier, dailyLimit, expiresAt) {
  els.editVchOriginalCode.value = code;
  els.editVchCode.value = code;
  els.editVchWhatsapp.value = whatsapp === '-' ? '' : whatsapp;
  els.editVchTier.value = tier.toLowerCase();
  els.editVchDailyLimit.value = dailyLimit;
  els.editVchExpiresAt.value = expiresAt;

  els.editVchForm.hidden = false;
  els.editVchForm.scrollIntoView({ behavior: "smooth" });
};

els.cancelEditVchBtn.addEventListener("click", () => {
  els.editVchForm.hidden = true;
});

els.saveEditVchBtn.addEventListener("click", async () => {
  const code = els.editVchOriginalCode.value;
  const whatsapp = els.editVchWhatsapp.value.trim();
  const tier = els.editVchTier.value;
  const dailyLimit = parseInt(els.editVchDailyLimit.value, 10);
  const expiresAtVal = els.editVchExpiresAt.value;

  if (isNaN(dailyLimit) || dailyLimit <= 0) {
    return showToast("Limit harian generate harus berupa angka positif!", "warn");
  }
  if (!expiresAtVal) {
    return showToast("Tanggal kedaluwarsa harus diisi!", "warn");
  }

  // Convert local YYYY-MM-DD input date to ISO at 23:59:59 local time
  const expiresAt = new Date(`${expiresAtVal}T23:59:59`).toISOString();

  try {
    await api(`/api/admin/vouchers/${encodeURIComponent(code)}`, {
      method: "PUT",
      body: JSON.stringify({ tier, whatsapp, dailyLimit, expiresAt }),
    });
    showToast("Voucher berhasil diperbarui!", "success");
    els.editVchForm.hidden = true;
    refreshVouchers().catch(() => {});
  } catch (err) {
    showToast(err.message, "error");
  }
});

// ─── Bulk actions (global functions called via inline onclick/onchange) ───────

window.toggleSelectAll = function(checkbox) {
  const isChecked = checkbox.checked;
  const chks = document.querySelectorAll("#account-list .acc-select-chk");
  chks.forEach((chk) => { chk.checked = isChecked; });
  const deleteBtn = document.getElementById("delete-selected-btn");
  const archiveBtn = document.getElementById("archive-selected-btn");
  const visible = isChecked && chks.length > 0;
  if (deleteBtn) deleteBtn.style.display = visible ? "inline-block" : "none";
  if (archiveBtn) archiveBtn.style.display = visible ? "inline-block" : "none";
};

window.archiveSelectedAccounts = async function() {
  const checkedChks = document.querySelectorAll("#account-list .acc-select-chk:checked");
  if (!checkedChks.length) {
    showToast("Tidak ada akun yang dipilih!", "warn");
    return;
  }
  
  const confirmed = await showConfirm("Tambahkan " + checkedChks.length + " akun terpilih ke archive?");
  if (!confirmed) return;

  const btn = document.getElementById("archive-selected-btn");
  const deleteBtn = document.getElementById("delete-selected-btn");
  if (btn) { btn.disabled = true; btn.textContent = "Memindahkan..."; }

  try {
    const ids = Array.from(checkedChks).map((chk) => chk.dataset.id);
    const data = await api("/api/admin/accounts/archive-multiple", {
      method: "POST",
      body: JSON.stringify({ ids }),
    });
    showToast("Berhasil memindahkan " + (data.archived || ids.length) + " akun ke archive!", "success");
    const selAll = document.getElementById("select-all-chk");
    if (selAll) selAll.checked = false;
    if (btn) btn.style.display = "none";
    if (deleteBtn) deleteBtn.style.display = "none";
    refresh();
  } catch (err) {
    showToast("Gagal archive akun: " + err.message, "error");
  } finally {
    if (btn) { btn.disabled = false; btn.textContent = "🗃️ Archive Terpilih"; }
  }
};

window.deleteSelectedAccounts = async function() {
  const checkedChks = document.querySelectorAll("#account-list .acc-select-chk:checked");
  if (!checkedChks.length) {
    showToast("Tidak ada akun yang dipilih!", "warn");
    return;
  }
  
  const confirmed = await showConfirm("Hapus " + checkedChks.length + " akun terpilih?");
  if (!confirmed) return;

  const btn = document.getElementById("delete-selected-btn");
  const archiveBtn = document.getElementById("archive-selected-btn");
  if (btn) { btn.disabled = true; btn.textContent = "🗑️ Menghapus..."; }

  try {
    const ids = Array.from(checkedChks).map((chk) => chk.dataset.id);
    await api("/api/admin/accounts/delete-multiple", {
      method: "POST",
      body: JSON.stringify({ ids }),
    });
    showToast("Berhasil menghapus " + ids.length + " akun terpilih!", "success");
    const selAll = document.getElementById("select-all-chk");
    if (selAll) selAll.checked = false;
    if (btn) btn.style.display = "none";
    if (archiveBtn) archiveBtn.style.display = "none";
    refresh();
  } catch (err) {
    showToast("Gagal menghapus: " + err.message, "error");
  } finally {
    if (btn) { btn.disabled = false; btn.textContent = "🗑️ Hapus Terpilih"; }
  }
};


window.deleteAllArchive = async function() {
  const password = await showPasswordPrompt();
  if (password === null) return; // User cancelled
  
  const correctPassword = sessionStorage.getItem(ADMIN_KEY) || adminPass;
  if (password !== correctPassword) {
    showToast("Gagal: Password admin salah!", "error");
    return;
  }
  
  if (!await showConfirm("Apakah Anda benar-benar yakin ingin menghapus SELURUH akun di archive?")) {
    return;
  }
  
  const btn = document.getElementById("delete-all-archive-btn");
  if (btn) { btn.disabled = true; btn.textContent = "🗑️ Menghapus..."; }
  
  try {
    const res = await api("/api/admin/accounts/archive/delete-all", {
      method: "POST",
    });
    showToast(`Berhasil menghapus ${res.deleted} akun dari archive.`, "success");
    refresh();
  } catch (err) {
    showToast("Gagal menghapus archive: " + err.message, "error");
  } finally {
    if (btn) { btn.disabled = false; btn.textContent = "🗑️ Hapus Semua Arsip"; }
  }
};

window.bulkReviveExpiredAccounts = async function() {
  if (!await showConfirm("Apakah Anda ingin memicu Bulk Revive untuk seluruh akun expired di Pool?")) {
    return;
  }
  
  const btn = document.getElementById("bulk-revive-btn");
  if (btn) { btn.disabled = true; btn.textContent = "🔄 Memulai..."; }
  
  try {
    const res = await api("/api/admin/auto-token/run", {
      method: "POST",
      body: JSON.stringify({ force: true, mode: "revive_only" }),
    });
    showToast("Bulk Revive berhasil dipicu! Pantau log di bawah.", "success");
    appendLog("▶ Memulai proses bulk revive akun expired...", "info");
  } catch (err) {
    showToast("Gagal memicu Bulk Revive: " + err.message, "error");
  } finally {
    if (btn) { btn.disabled = false; btn.textContent = "🔄 Bulk Revive"; }
  }
};

window.deleteAllPoolAccounts = async function() {
  const password = await showPasswordPrompt();
  if (password === null) return;
  
  const correctPassword = sessionStorage.getItem(ADMIN_KEY) || adminPass;
  if (password !== correctPassword) {
    showToast("Gagal: Password admin salah!", "error");
    return;
  }
  
  if (!await showConfirm("Apakah Anda benar-benar yakin ingin menghapus SELURUH akun di Pool?")) {
    return;
  }
  
  const btn = document.getElementById("delete-all-pool-btn");
  if (btn) { btn.disabled = true; btn.textContent = "🗑️ Menghapus..."; }
  
  try {
    const res = await api("/api/admin/accounts/pool/delete-all", {
      method: "POST",
    });
    showToast(`Berhasil menghapus ${res.deleted} akun dari Pool.`, "success");
    refresh();
  } catch (err) {
    showToast("Gagal menghapus Pool: " + err.message, "error");
  } finally {
    if (btn) { btn.disabled = false; btn.textContent = "🗑️ Hapus Semua Akun"; }
  }
};

// Event delegation for account actions (delete / edit)
els.accountList.addEventListener("click", async (e) => {
  const btn = e.target.closest("button[data-act]");
  if (!btn) return;

  const act = btn.dataset.act;
  const id = btn.dataset.id;

  if (act === "del") {
    const confirmed = await showConfirm("Hapus akun ini?");
    if (!confirmed) return;
    try {
      await api(`/api/admin/accounts/${id}`, { method: "DELETE" });
      showToast("Akun berhasil dihapus!", "success");
      refresh();
    } catch (err) { showToast(err.message, "error"); }
  } else if (act === "edit") {
    const a = currentAccounts.find((x) => x.id === id);
    if (!a) return;
    els.editId.value = a.id;
    els.editToken.value = "";
    els.editToken.placeholder = `(token tersembunyi: ${a.tokenPreview}) — kosongkan jika tidak diubah`;
    els.editRecipe.value = a.recipeId || "";
    els.editLabel.value = a.label || "";
    els.editForm.hidden = false;
    els.editForm.scrollIntoView({ behavior: "smooth" });
  } else if (act === "revive") {
    const email = btn.dataset.email || id;
    if (!await showConfirm(`Revive akun ${email} via Figma Sign-In? Bot akan login ulang otomatis.`)) return;
    btn.disabled = true;
    btn.textContent = "⏳";
    try {
      const res = await api(`/api/admin/accounts/${id}/revive`, { method: "POST" });
      if (res.ok) {
        showToast(`✅ ${email} berhasil di-revive!`, "success");
      } else {
        showToast(`❌ ${res.error || "Gagal revive"}`, "error");
      }
    } catch (err) {
      showToast(`❌ Gagal revive: ${err.message}`, "error");
    }
    btn.disabled = false;
    btn.textContent = "🔄";
    refresh();
  }
});

// Event delegation for checkbox changes
els.accountList.addEventListener("change", (e) => {
  if (e.target.classList.contains("acc-select-chk")) {
    updatePoolSelectionActionButtons();
  }
});

// Event delegation for archive restore action
els.archiveList.addEventListener("click", async (e) => {
  const btn = e.target.closest("button[data-restore-id]");
  if (!btn) return;

  const restoreId = btn.dataset.restoreId;
  const confirmed = await showConfirm("Pulihkan akun ini kembali ke pool utama?");
  if (!confirmed) return;

  try {
    await api(`/api/admin/accounts/${restoreId}/restore`, {
      method: "POST",
      body: JSON.stringify({ force: true }),
    });
    showToast("Akun berhasil dipulihkan!", "success");
    refresh();
  } catch (err) {
    showToast(err.message, "error");
  }
});

// ─── Owner Settings & Reseller Portal ────────────────────────────────────────

async function loadOwnerSettings() {
  if (adminRole !== "owner") return;
  try {
    const settings = await api("/api/admin/owner/settings");
    if (els.ownerKasirPassword) els.ownerKasirPassword.value = settings.kasirPassword || "";
    if (els.ownerPricePro) els.ownerPricePro.value = settings.prices?.proPrice || 0;
    if (els.ownerPriceReseller) els.ownerPriceReseller.value = settings.prices?.resellerPrice || 0;
    if (els.ownerPriceVip) els.ownerPriceVip.value = settings.prices?.vipPrice || 0;
    if (els.ownerPriceResellerVip) els.ownerPriceResellerVip.value = settings.prices?.resellerVipPrice || 0;
    renderResellers(settings.resellers || []);
    renderOwnerFullAccessSection(settings.resellers || []);
    loadFullAccessLogs().catch(() => {});
  } catch (err) {
    showToast("Gagal memuat pengaturan: " + err.message, "error");
  }
}

function renderResellers(resellers) {
  if (!els.resellerList) return;
  if (!resellers.length) {
    els.resellerList.innerHTML = `<div class="empty-accounts">Belum ada mitra reseller. Tambahkan di atas.</div>`;
    return;
  }
  els.resellerList.innerHTML = "";
  for (const r of resellers) {
    const row = document.createElement("div");
    row.className = "account-row";
    row.style.gridTemplateColumns = "1fr auto";
    
    const allowBot = r.allowBot ?? true;
    const allowPool = r.allowPool ?? true;
    const allowArchive = r.allowArchive ?? true;
    const debtEnabled = r.debtEnabled ?? false;
    const debtLimit = r.debtLimit ?? 0;
    const isDebt = (r.balance || 0) < 0;

    // Build debt badge
    let debtBadge = "";
    if (debtEnabled) {
      const debtColor = isDebt ? '#dc2626' : '#f59e0b';
      const debtText = isDebt ? `Utang: Rp ${Math.abs(r.balance).toLocaleString('id-ID')} / Rp ${debtLimit.toLocaleString('id-ID')}` : `Batas Utang: Rp ${debtLimit.toLocaleString('id-ID')}`;
      debtBadge = `<span class="badge badge-idle" style="animation: none; background: ${debtColor}; color: #fff;">⚠ ${debtText}</span>`;
    }

    // Full-access status badges
    let fullAccessBadge = "";
    if (r.fullAccessGranted) {
      fullAccessBadge = `<span class="badge badge-idle" style="animation: none; background: #065f46; color: #6ee7b7;">🔓 Akses Penuh Aktif</span>`;
    } else if (r.fullAccessRequested) {
      fullAccessBadge = `<span class="badge badge-idle" style="animation: none; background: #78350f; color: #fbbf24;">⏳ Minta Akses Penuh</span>`;
    }

    let pricingDetails = "";
    if (r.customResellerPrice !== null || r.customSrp !== null || r.customResellerVipPrice !== null || r.customVipSrp !== null) {
      const modalStr = r.customResellerPrice !== null ? `Rp ${r.customResellerPrice.toLocaleString('id-ID')}` : "Global";
      const srpStr = r.customSrp !== null ? `Rp ${r.customSrp.toLocaleString('id-ID')}` : "Global";
      const modalVipStr = r.customResellerVipPrice !== null ? `Rp ${r.customResellerVipPrice.toLocaleString('id-ID')}` : "Global";
      const srpVipStr = r.customVipSrp !== null ? `Rp ${r.customVipSrp.toLocaleString('id-ID')}` : "Global";
      pricingDetails = ` <span style="font-size: 0.8rem; color: #fbbf24;">(Harga Custom - Pro Modal: ${modalStr}, Pro SRP: ${srpStr} | VIP Modal: ${modalVipStr}, VIP SRP: ${srpVipStr})</span>`;
    }

    row.innerHTML = `
      <div class="acc-info">
        <div class="acc-label" style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
          <span>${escapeHtml(r.name)}</span>
          <span class="badge badge-idle" style="animation: none; background: #1e3a8a; color: #93c5fd;">Saldo: Rp ${(r.balance || 0).toLocaleString('id-ID')}</span>
          <span class="badge badge-idle" style="animation: none; background: #064e3b; color: #6ee7b7;">Komisi: Rp ${(r.totalCommission || 0).toLocaleString('id-ID')}</span>
          <span class="badge badge-idle" style="animation: none; display: none;">Quota: ${r.quota}</span>
          ${debtBadge}
          ${fullAccessBadge}
          ${pricingDetails}
        </div>
        <div class="acc-meta" style="margin-top: 4px;">
          <span>Password: <code>${escapeHtml(r.password)}</code></span>
          <span class="dot">·</span>
          <span>Akses Bot: <strong style="color: ${allowBot ? 'var(--success)' : 'var(--accent)'}">${allowBot ? 'Aktif' : 'Nonaktif'}</strong></span>
          <span class="dot">·</span>
          <span>Akses Pool: <strong style="color: ${allowPool ? 'var(--success)' : 'var(--accent)'}">${allowPool ? 'Aktif' : 'Nonaktif'}</strong></span>
          <span class="dot">·</span>
          <span>Akses Archive: <strong style="color: ${allowArchive ? 'var(--success)' : 'var(--accent)'}">${allowArchive ? 'Aktif' : 'Nonaktif'}</strong></span>
        </div>
      </div>
      <div class="acc-actions">
        <button type="button" class="ghost small" onclick="openEditReseller('${escapeHtml(r.id)}', '${escapeHtml(r.name)}', '${escapeHtml(r.password)}', ${r.quota}, ${allowBot}, ${allowPool}, ${allowArchive}, ${r.balance || 0}, ${r.customResellerPrice !== null ? r.customResellerPrice : 'null'}, ${r.customSrp !== null ? r.customSrp : 'null'}, ${r.customResellerVipPrice !== null ? r.customResellerVipPrice : 'null'}, ${r.customVipSrp !== null ? r.customVipSrp : 'null'}, ${debtEnabled}, ${debtLimit})">✏️</button>
        <button type="button" class="ghost small danger" onclick="deleteReseller('${escapeHtml(r.id)}')">✕ Hapus</button>
      </div>
    `;
    els.resellerList.appendChild(row);
  }
}

window.openEditReseller = function(id, name, password, quota, allowBot, allowPool, allowArchive, balance, customResellerPrice, customSrp, customResellerVipPrice, customVipSrp, debtEnabled, debtLimit) {
  if (!els.editResellerForm) return;
  els.editResellerId.value = id;
  els.editResellerName.value = name;
  els.editResellerPassword.value = "";
  els.editResellerPassword.placeholder = `(password tersembunyi) — isi untuk mengubah`;
  els.editResellerQuota.value = quota;
  els.editResellerBalance.value = balance ?? 0;
  els.editResellerCustomPrice.value = customResellerPrice !== null && customResellerPrice !== undefined ? customResellerPrice : "";
  els.editResellerCustomSrp.value = customSrp !== null && customSrp !== undefined ? customSrp : "";
  els.editResellerCustomPriceVip.value = customResellerVipPrice !== null && customResellerVipPrice !== undefined ? customResellerVipPrice : "";
  els.editResellerCustomSrpVip.value = customVipSrp !== null && customVipSrp !== undefined ? customVipSrp : "";
  els.editResellerAllowBot.checked = Boolean(allowBot);
  els.editResellerAllowPool.checked = Boolean(allowPool);
  els.editResellerAllowArchive.checked = Boolean(allowArchive);
  els.editResellerDebtEnabled.checked = Boolean(debtEnabled);
  els.editResellerDebtLimit.value = debtLimit || 0;
  
  els.editResellerForm.hidden = false;
  els.editResellerForm.scrollIntoView({ behavior: "smooth" });
};

window.deleteReseller = async function(id) {
  const confirmed = await showConfirm("Hapus mitra reseller ini secara permanen?");
  if (!confirmed) return;
  try {
    await api(`/api/admin/owner/resellers/${id}`, { method: "DELETE" });
    showToast("Reseller berhasil dihapus", "success");
    loadOwnerSettings().catch(() => {});
  } catch (err) {
    showToast(err.message, "error");
  }
};

if (els.ownerSaveSettingsBtn) {
  els.ownerSaveSettingsBtn.addEventListener("click", async () => {
    const kasirPassword = els.ownerKasirPassword.value.trim();
    const proPrice = parseFloat(els.ownerPricePro.value);
    const resellerPrice = parseFloat(els.ownerPriceReseller.value);
    const vipPrice = parseFloat(els.ownerPriceVip.value);
    const resellerVipPrice = parseFloat(els.ownerPriceResellerVip.value);

    if (!kasirPassword) {
      return showToast("Password kasir tidak boleh kosong!", "warn");
    }

    try {
      await api("/api/admin/owner/settings", {
        method: "POST",
        body: JSON.stringify({
          kasirPassword,
          prices: {
            proPrice,
            resellerPrice,
            vipPrice,
            resellerVipPrice
          }
        })
      });
      showToast("Pengaturan global berhasil disimpan", "success");
      loadOwnerSettings().catch(() => {});
    } catch (err) {
      showToast(err.message, "error");
    }
  });
}

if (els.createResellerBtn) {
  els.createResellerBtn.addEventListener("click", async () => {
    const name = els.resellerName.value.trim();
    const password = els.resellerPassword.value.trim();
    const quota = parseInt(els.resellerQuota.value, 10) || 0;
    const balance = parseFloat(els.resellerBalance.value) || 0;
    const customResellerPrice = els.resellerCustomPrice.value !== "" ? parseFloat(els.resellerCustomPrice.value) : null;
    const customSrp = els.resellerCustomSrp.value !== "" ? parseFloat(els.resellerCustomSrp.value) : null;
    const customResellerVipPrice = els.resellerCustomPriceVip.value !== "" ? parseFloat(els.resellerCustomPriceVip.value) : null;
    const customVipSrp = els.resellerCustomSrpVip.value !== "" ? parseFloat(els.resellerCustomSrpVip.value) : null;
    const allowBot = els.resellerAllowBot.checked;
    const allowPool = els.resellerAllowPool.checked;
    const allowArchive = els.resellerAllowArchive.checked;
    const debtEnabled = els.resellerDebtEnabled.checked;
    const debtLimit = parseFloat(els.resellerDebtLimit.value) || 0;

    if (!name || !password) {
      return showToast("Nama dan password reseller wajib diisi!", "warn");
    }

    try {
      await api("/api/admin/owner/resellers", {
        method: "POST",
        body: JSON.stringify({ name, password, quota, balance, customResellerPrice, customSrp, customResellerVipPrice, customVipSrp, allowBot, allowPool, allowArchive, debtEnabled, debtLimit })
      });
      showToast("Mitra reseller baru berhasil ditambahkan", "success");
      els.resellerName.value = "";
      els.resellerPassword.value = "";
      els.resellerQuota.value = "10";
      els.resellerBalance.value = "500000";
      els.resellerCustomPrice.value = "";
      els.resellerCustomSrp.value = "";
      els.resellerCustomPriceVip.value = "";
      els.resellerCustomSrpVip.value = "";
      els.resellerAllowBot.checked = true;
      els.resellerAllowPool.checked = true;
      els.resellerAllowArchive.checked = true;
      els.resellerDebtEnabled.checked = false;
      els.resellerDebtLimit.value = "";
      loadOwnerSettings().catch(() => {});
    } catch (err) {
      showToast(err.message, "error");
    }
  });
}

if (els.cancelEditResellerBtn) {
  els.cancelEditResellerBtn.addEventListener("click", () => {
    if (els.editResellerForm) els.editResellerForm.hidden = true;
  });
}

if (els.saveEditResellerBtn) {
  els.saveEditResellerBtn.addEventListener("click", async () => {
    const id = els.editResellerId.value;
    const name = els.editResellerName.value.trim();
    const password = els.editResellerPassword.value.trim();
    const quota = parseInt(els.editResellerQuota.value, 10) || 0;
    const balance = parseFloat(els.editResellerBalance.value) || 0;
    const customResellerPrice = els.editResellerCustomPrice.value !== "" ? parseFloat(els.editResellerCustomPrice.value) : null;
    const customSrp = els.editResellerCustomSrp.value !== "" ? parseFloat(els.editResellerCustomSrp.value) : null;
    const customResellerVipPrice = els.editResellerCustomPriceVip.value !== "" ? parseFloat(els.editResellerCustomPriceVip.value) : null;
    const customVipSrp = els.editResellerCustomSrpVip.value !== "" ? parseFloat(els.editResellerCustomSrpVip.value) : null;
    const allowBot = els.editResellerAllowBot.checked;
    const allowPool = els.editResellerAllowPool.checked;
    const allowArchive = els.editResellerAllowArchive.checked;
    const debtEnabled = els.editResellerDebtEnabled.checked;
    const debtLimit = parseFloat(els.editResellerDebtLimit.value) || 0;

    if (!name) {
      return showToast("Nama reseller tidak boleh kosong!", "warn");
    }

    const payload = { 
      name, 
      quota, 
      balance, 
      customResellerPrice, 
      customSrp, 
      customResellerVipPrice,
      customVipSrp,
      allowBot, 
      allowPool, 
      allowArchive,
      debtEnabled,
      debtLimit
    };
    if (password) payload.password = password;

    try {
      await api(`/api/admin/owner/resellers/${id}`, {
        method: "PUT",
        body: JSON.stringify(payload)
      });
      showToast("Data reseller berhasil diperbarui", "success");
      if (els.editResellerForm) els.editResellerForm.hidden = true;
      loadOwnerSettings().catch(() => {});
    } catch (err) {
      showToast(err.message, "error");
    }
  });
}

if (els.saveMitraSrpBtn) {
  els.saveMitraSrpBtn.addEventListener("click", async () => {
    const customSrp = els.mitraCustomSrp.value !== "" ? parseFloat(els.mitraCustomSrp.value) : null;
    const customVipSrp = els.mitraCustomSrpVip.value !== "" ? parseFloat(els.mitraCustomSrpVip.value) : null;

    if (customSrp !== null && customSrp < globalProPriceVal) {
      return showToast(`Dilarang menjual Pro di bawah harga SRP Global! (Minimum: Rp ${globalProPriceVal.toLocaleString('id-ID')})`, "warn");
    }
    if (customVipSrp !== null && customVipSrp < globalVipPriceVal) {
      return showToast(`Dilarang menjual VIP di bawah harga SRP Global! (Minimum: Rp ${globalVipPriceVal.toLocaleString('id-ID')})`, "warn");
    }

    try {
      const res = await api("/api/admin/reseller/settings", {
        method: "PUT",
        body: JSON.stringify({ customSrp, customVipSrp })
      });
      resellerCustomSrpVal = res.customSrp !== null ? String(res.customSrp) : "";
      resellerCustomVipSrpVal = res.customVipSrp !== null ? String(res.customVipSrp) : "";
      sessionStorage.setItem("weavy_reseller_custom_srp", resellerCustomSrpVal);
      sessionStorage.setItem("weavy_reseller_custom_vip_srp", resellerCustomVipSrpVal);
      
      showToast("Markup harga jual SRP berhasil disimpan!", "success");
    } catch (err) {
      showToast(err.message, "error");
    }
  });
}

// ─── Bootstrap ──────────────────────────────────────────────────────────────

let currentMaintenanceState = null;

async function refreshMaintenanceStatus() {
  try {
    const maintenance = await api("/api/admin/maintenance");
    currentMaintenanceState = maintenance;
    
    const statusText = els.adminMaintenanceStatusText;
    const detailText = els.adminMaintenanceDetailText;
    const adminBar = document.getElementById("maintenance-admin-bar");

    if (maintenance.active) {
      if (statusText) {
        statusText.textContent = "MAINTENANCE (AKTIF)";
        statusText.style.color = "#ef4444";
      }
      if (detailText) {
        let durStr = maintenance.duration;
        if (maintenance.expiresAt) {
          const ms = new Date(maintenance.expiresAt).getTime() - Date.now();
          if (ms > 0) {
            const min = Math.ceil(ms / 60000);
            durStr = `Estimasi selesai: ${min} menit lagi`;
          }
        }
        detailText.textContent = `Alasan: "${maintenance.reason}" (${durStr})`;
      }
      if (adminBar) {
        adminBar.style.background = "#291515";
        adminBar.style.borderColor = "#ef4444";
      }
    } else {
      if (statusText) {
        statusText.textContent = "Normal";
        statusText.style.color = "#fbbf24";
      }
      if (detailText) {
        detailText.textContent = "Semua fitur berjalan normal.";
      }
      if (adminBar) {
        adminBar.style.background = "#1a1510";
        adminBar.style.borderColor = "#f59e0b";
      }
    }
  } catch (err) {
    console.error("Gagal memuat status maintenance:", err);
  }
}

// Maintenance Modal events
if (els.btnToggleMaintenanceModal) {
  els.btnToggleMaintenanceModal.addEventListener("click", async () => {
    await refreshMaintenanceStatus();
    if (currentMaintenanceState) {
      els.mActive.checked = Boolean(currentMaintenanceState.active);
      if (els.mTitle) els.mTitle.value = currentMaintenanceState.title || "Server Sedang Pemeliharaan";
      if (els.mDescription) els.mDescription.value = currentMaintenanceState.description || "Kami sedang melakukan peningkatan sistem. Generator diistirahatkan sementara untuk memastikan kestabilan layanan.";
      els.mReason.value = currentMaintenanceState.reason || "";
      
      const dur = currentMaintenanceState.duration || "60";
      if (["30", "60", "120", "180"].includes(dur)) {
        els.mDurationSelect.value = dur;
        els.mDurationCustomWrapper.style.display = "none";
      } else {
        els.mDurationSelect.value = "custom";
        els.mDurationCustom.value = dur;
        els.mDurationCustomWrapper.style.display = "block";
      }
    }
    els.maintenanceModal.classList.add("active");
  });
}

if (els.mDurationSelect) {
  els.mDurationSelect.addEventListener("change", () => {
    const isCustom = els.mDurationSelect.value === "custom";
    els.mDurationCustomWrapper.style.display = isCustom ? "block" : "none";
  });
}

if (els.mCancelBtn) {
  els.mCancelBtn.addEventListener("click", () => {
    els.maintenanceModal.classList.remove("active");
  });
}

if (els.mSaveBtn) {
  els.mSaveBtn.addEventListener("click", async () => {
    const active = els.mActive.checked;
    const title = els.mTitle ? els.mTitle.value.trim() : "Server Sedang Pemeliharaan";
    const description = els.mDescription ? els.mDescription.value.trim() : "Kami sedang melakukan peningkatan sistem. Generator diistirahatkan sementara untuk memastikan kestabilan layanan.";
    const reason = els.mReason.value.trim() || "Pemeliharaan sistem berkala";
    
    let duration = els.mDurationSelect.value;
    let expiresAt = null;

    if (duration === "custom") {
      duration = els.mDurationCustom.value.trim() || "1 jam";
    } else {
      const minutes = parseInt(duration, 10);
      duration = minutes < 60 ? `${minutes} menit` : `${minutes / 60} jam`;
      if (active) {
        expiresAt = new Date(Date.now() + minutes * 60 * 1000).toISOString();
      }
    }

    try {
      await api("/api/admin/maintenance", {
        method: "POST",
        body: JSON.stringify({ active, reason, duration, expiresAt, title, description })
      });
      showToast("Status maintenance berhasil disimpan!", "success");
      els.maintenanceModal.classList.remove("active");
      refreshMaintenanceStatus();
    } catch (err) {
      showToast("Gagal menyimpan maintenance: " + err.message, "error");
    }
  });
}

// ─── VIP Promo Settings ──────────────────────────────────────────────────────
async function refreshPromoStatus() {
  try {
    const res = await api("/api/admin/promo/settings");
    if (res.ok && res.promo) {
      const activeChk = document.getElementById("promo-active-chk");
      const titleInput = document.getElementById("promo-title");
      const btnTextInput = document.getElementById("promo-btn-text");
      const btnLinkInput = document.getElementById("promo-btn-link");
      const mediaUrlInput = document.getElementById("promo-media-url");
      const mediaTypeInput = document.getElementById("promo-media-type");
      const descTextarea = document.getElementById("promo-description");
      const fileNameSpan = document.getElementById("promo-file-name");

      if (activeChk) activeChk.checked = Boolean(res.promo.active);
      if (titleInput) titleInput.value = res.promo.title || "";
      if (btnTextInput) btnTextInput.value = res.promo.btnText || "";
      if (btnLinkInput) btnLinkInput.value = res.promo.btnLink || "";
      if (mediaUrlInput) mediaUrlInput.value = res.promo.mediaUrl || "";
      if (mediaTypeInput) mediaTypeInput.value = res.promo.mediaType || "image";
      if (descTextarea) {
        descTextarea.value = res.promo.description || "";
        updateDescPreview(descTextarea.value);
      }
      
      if (res.promo.mediaUrl) {
        if (fileNameSpan) {
          const parts = res.promo.mediaUrl.split("/");
          fileNameSpan.textContent = parts[parts.length - 1];
        }
        renderPromoPreview(res.promo.mediaUrl, res.promo.mediaType);
      } else {
        if (fileNameSpan) fileNameSpan.textContent = "Belum ada file dipilih";
        const previewContainer = document.getElementById("promo-preview-container");
        if (previewContainer) {
          previewContainer.style.display = "none";
          previewContainer.innerHTML = '<span id="promo-preview-placeholder" style="color: var(--muted); font-size: 0.85rem;">Pratinjau Media</span>';
        }
      }
    }
  } catch (err) {
    console.error("Gagal memuat status promo:", err);
  }
}

function renderPromoPreview(url, type) {
  const previewContainer = document.getElementById("promo-preview-container");
  if (!previewContainer) return;

  previewContainer.style.display = "flex";
  previewContainer.innerHTML = "";

  if (type === "video") {
    const video = document.createElement("video");
    video.src = url;
    video.autoplay = true;
    video.controls = true;
    video.muted = true;
    video.loop = true;
    video.style.width = "100%";
    video.style.height = "100%";
    video.style.objectFit = "contain";
    previewContainer.appendChild(video);
  } else {
    const img = document.createElement("img");
    img.src = url;
    img.style.width = "100%";
    img.style.height = "100%";
    img.style.objectFit = "contain";
    previewContainer.appendChild(img);
  }
}

// File upload handler for local promo media
const promoFileInput = document.getElementById("promo-file-input");
if (promoFileInput) {
  promoFileInput.addEventListener("change", async (e) => {
    const file = e.target.files[0];
    if (!file) return;

    const fileNameSpan = document.getElementById("promo-file-name");
    if (fileNameSpan) fileNameSpan.textContent = `Mengunggah: ${file.name}...`;

    const formData = new FormData();
    formData.append("file", file);

    try {
      const res = await fetch("/api/admin/promo/upload", {
        method: "POST",
        headers: {
          "x-admin-password": sessionStorage.getItem(ADMIN_KEY) || ""
        },
        body: formData
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || "Gagal mengunggah file");

      if (fileNameSpan) fileNameSpan.textContent = file.name;
      
      const mediaUrlInput = document.getElementById("promo-media-url");
      const mediaTypeInput = document.getElementById("promo-media-type");
      if (mediaUrlInput) mediaUrlInput.value = data.url;
      if (mediaTypeInput) mediaTypeInput.value = data.mediaType;

      renderPromoPreview(data.url, data.mediaType);
      showToast("Media promo berhasil diunggah!", "success");
    } catch (err) {
      if (fileNameSpan) fileNameSpan.textContent = "Gagal mengunggah";
      showToast("Upload gagal: " + err.message, "error");
    }
  });
}

// Save settings handler
const savePromoBtn = document.getElementById("save-promo-btn");
if (savePromoBtn) {
  savePromoBtn.addEventListener("click", async () => {
    const active = document.getElementById("promo-active-chk")?.checked;
    const title = document.getElementById("promo-title")?.value || "";
    const btnText = document.getElementById("promo-btn-text")?.value || "";
    const btnLink = document.getElementById("promo-btn-link")?.value || "";
    const mediaUrl = document.getElementById("promo-media-url")?.value || "";
    const mediaType = document.getElementById("promo-media-type")?.value || "image";
    const description = document.getElementById("promo-description")?.value || "";

    try {
      await api("/api/admin/promo/settings", {
        method: "POST",
        body: JSON.stringify({ active, title, btnText, btnLink, mediaUrl, mediaType, description })
      });
      showToast("Pengaturan promo VIP berhasil disimpan!", "success");
    } catch (err) {
      showToast("Gagal menyimpan pengaturan: " + err.message, "error");
    }
  });
}

// Live Preview for Promo Description Text
const promoDescTextarea = document.getElementById("promo-description");
if (promoDescTextarea) {
  promoDescTextarea.addEventListener("input", (e) => {
    updateDescPreview(e.target.value);
  });
}

function updateDescPreview(text) {
  const previewDiv = document.getElementById("promo-desc-preview");
  if (previewDiv) {
    previewDiv.innerHTML = formatPromoDescription(text) || '<span style="color: var(--muted); font-size: 0.85rem; font-style: italic;">Belum ada deskripsi</span>';
  }
}

function formatPromoDescription(text) {
  if (!text) return "";
  const highlightWords = [
    "VIP", "PRO", "GRATIS", "FREE", "RENDER", "LIMIT", 
    "TANPA BATAS", "DISKON", "BONUS", "100%", "UNLIMITED",
    "SPESIAL", "KLAIM", "AKTIF", "SUKSES", "VOUCHER"
  ];
  const lines = text.split("\n").map(l => l.trim()).filter(l => l.length > 0);
  if (lines.length === 0) return "";
  let html = "";
  let headerProcessed = false;
  let subheaderProcessed = false;
  let listItems = [];
  
  function highlightText(t) {
    let formatted = t;
    highlightWords.forEach(word => {
      const escapedWord = word.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
      const regex = new RegExp(`\\b${escapedWord}\\b`, "gi");
      formatted = formatted.replace(regex, (match) => `<strong style="color: #ffaa00; font-weight: 800;">${match}</strong>`);
    });
    return formatted;
  }

  for (let i = 0; i < lines.length; i++) {
    let line = lines[i];
    if (line.startsWith("-") || line.startsWith("*") || line.startsWith("•") || line.startsWith("✓")) {
      const cleanLine = line.replace(/^[-*•✓]\s*/, "");
      listItems.push(highlightText(cleanLine));
    } else {
      if (listItems.length > 0) {
        html += renderPromoList(listItems);
        listItems = [];
      }
      if (!headerProcessed) {
        html += `<h3 style="margin: 0 0 8px 0; font-size: 17px; font-weight: 800; color: #ffffff; letter-spacing: 0.5px; text-transform: uppercase; text-shadow: 0 2px 4px rgba(0,0,0,0.5);">${highlightText(line)}</h3>`;
        headerProcessed = true;
      } else if (!subheaderProcessed && lines.length > 2) {
        html += `<p style="margin: 0 0 12px 0; font-size: 13.5px; font-weight: 600; color: #b3b3b3; line-height: 1.4;">${highlightText(line)}</p>`;
        subheaderProcessed = true;
      } else {
        html += `<p style="margin: 0 0 10px 0; font-size: 13px; font-weight: 500; color: #cccccc; line-height: 1.5; text-align: center;">${highlightText(line)}</p>`;
      }
    }
  }
  if (listItems.length > 0) {
    html += renderPromoList(listItems);
  }
  return html;
}

function renderPromoList(items) {
  let listHtml = `<div style="text-align: left; display: inline-block; max-width: 100%; margin: 0 auto 12px auto;"><ul style="list-style: none; padding: 0; margin: 0;">`;
  items.forEach(item => {
    listHtml += `
      <li style="margin-bottom: 6px; display: flex; align-items: flex-start; gap: 6px; font-size: 13px; color: #e5e5e5; line-height: 1.4;">
        <span style="color: #ffaa00; font-size: 13px; flex-shrink: 0; margin-top: 1px;">⚡</span>
        <span>${item}</span>
      </li>`;
  });
  listHtml += `</ul></div>`;
  return listHtml;
}

// ═══ Full Access Management (Mitra ↔ Owner) ═══

// Render full-access controls for mitra in the reseller info bar
function renderMitraFullAccessControls() {
  if (!els.fullAccessMitraControls) return;
  els.fullAccessMitraControls.style.display = "flex";

  const badge = els.fullAccessStatusBadge;
  const reqBtn = els.fullAccessRequestBtn;
  const pendingText = els.fullAccessPendingText;

  // Reset all
  if (badge) { badge.style.display = "none"; badge.textContent = ""; }
  if (reqBtn) reqBtn.style.display = "none";
  if (pendingText) pendingText.style.display = "none";

  if (fullAccessGranted) {
    // Already have full access
    if (badge) {
      badge.style.display = "inline-block";
      badge.style.background = "#065f46";
      badge.style.color = "#6ee7b7";
      badge.textContent = "🔓 Akses Penuh Aktif";
      badge.title = `Disetujui pada: ${new Date(fullAccessGrantedAt).toLocaleString('id-ID')}`;
    }
  } else if (fullAccessRequested) {
    // Request pending
    if (pendingText) pendingText.style.display = "inline";
    if (badge) {
      badge.style.display = "inline-block";
      badge.style.background = "#78350f";
      badge.style.color = "#fbbf24";
      badge.textContent = "⏳ Menunggu Persetujuan";
    }
  } else {
    // Can request
    if (reqBtn) reqBtn.style.display = "inline-block";
  }
}

// Event: Mitra request full access
if (els.fullAccessRequestBtn) {
  els.fullAccessRequestBtn.addEventListener("click", async () => {
    try {
      const res = await api("/api/admin/reseller/request-full-access", { method: "POST" });
      if (res.ok) {
        fullAccessRequested = true;
        sessionStorage.setItem("weavy_full_access_requested", "true");
        showToast("Permintaan akses penuh telah diajukan. Owner akan menerima notifikasi.", "success");
        renderMitraFullAccessControls();
        // Log audit activity
        api("/api/admin/audit/access-log", {
          method: "POST",
          body: JSON.stringify({
            action: "Mengajukan permintaan akses penuh",
            description: `Mitra "${resellerNameStr}" mengajukan permintaan akses penuh.`
          })
        }).catch(() => {});
      }
    } catch (err) {
      showToast(err.message, "error");
    }
  });
}

// Render full-access management section for owner
function renderOwnerFullAccessSection(resellers) {
  if (adminRole !== "owner") return;

  // Render pending requests
  const pendingContainer = els.fullAccessPendingRequests;
  const pendingList = els.fullAccessPendingList;
  const pendingResellers = resellers.filter(r => r.fullAccessRequested && !r.fullAccessGranted);

  if (pendingResellers.length > 0 && pendingContainer && pendingList) {
    pendingContainer.style.display = "block";
    pendingList.innerHTML = "";
    for (const r of pendingResellers) {
      const card = document.createElement("div");
      card.style.cssText = "display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; background: rgba(251,191,36,0.08); border: 1px solid rgba(251,191,36,0.25); border-radius: 8px;";
      card.innerHTML = `
        <div>
          <strong style="color: var(--text);">${escapeHtml(r.name)}</strong>
          <div style="font-size: 0.75rem; color: var(--muted); margin-top: 2px;">Diminta: ${r.fullAccessRequestedAt ? new Date(r.fullAccessRequestedAt).toLocaleString('id-ID') : "-"}</div>
        </div>
        <div style="display: flex; gap: 6px;">
          <button type="button" class="primary small" style="background: #059669; border-color: #047857; padding: 0.35rem 0.8rem; width: auto;" onclick="window.grantFullAccess('${escapeHtml(r.id)}', '${escapeHtml(r.name)}')">✅ Setujui</button>
          <button type="button" class="ghost small danger" style="padding: 0.35rem 0.8rem; width: auto;" onclick="window.denyFullAccess('${escapeHtml(r.id)}', '${escapeHtml(r.name)}')">✕ Tolak</button>
        </div>
      `;
      pendingList.appendChild(card);
    }
  } else if (pendingContainer) {
    pendingContainer.style.display = "none";
  }

  // Render active full access
  const activeSection = els.fullAccessActiveListSection;
  const activeList = els.fullAccessActiveList;
  const activeResellers = resellers.filter(r => r.fullAccessGranted);

  if (activeResellers.length > 0 && activeSection && activeList) {
    activeSection.style.display = "block";
    activeList.innerHTML = "";
    for (const r of activeResellers) {
      const card = document.createElement("div");
      card.style.cssText = "display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; background: rgba(52,211,153,0.08); border: 1px solid rgba(52,211,153,0.25); border-radius: 8px;";
      card.innerHTML = `
        <div>
          <strong style="color: var(--text);">${escapeHtml(r.name)}</strong>
          <div style="font-size: 0.75rem; color: var(--muted); margin-top: 2px;">Disetujui: ${r.fullAccessGrantedAt ? new Date(r.fullAccessGrantedAt).toLocaleString('id-ID') : "-"} oleh ${escapeHtml(r.fullAccessGrantedBy || "Owner")}</div>
        </div>
        <button type="button" class="ghost small danger" style="padding: 0.35rem 0.8rem; width: auto;" onclick="window.revokeFullAccess('${escapeHtml(r.id)}', '${escapeHtml(r.name)}')">🔒 Cabut Akses</button>
      `;
      activeList.appendChild(card);
    }
  } else if (activeSection) {
    activeSection.style.display = "none";
  }

  // Show/hide full-access management section based on pending + active
  const ownerSection = document.getElementById("full-access-owner-section");
  if (ownerSection) {
    const hasContent = pendingResellers.length > 0 || activeResellers.length > 0;
    // Always show for owner — they should always see the log
  }
}

// Owner actions: grant, revoke, deny
window.grantFullAccess = async function(id, name) {
  const confirmed = await showConfirm(`Setujui akses penuh untuk mitra "${name}"? Mitra akan memiliki akses setara Owner.`);
  if (!confirmed) return;
  try {
    await api(`/api/admin/owner/resellers/${id}/grant-full-access`, { method: "POST" });
    showToast(`Akses penuh untuk "${name}" telah disetujui.`, "success");
    loadOwnerSettings().catch(() => {});
    loadFullAccessLogs().catch(() => {});
  } catch (err) {
    showToast(err.message, "error");
  }
};

window.revokeFullAccess = async function(id, name) {
  const confirmed = await showConfirm(`Cabut akses penuh dari mitra "${name}"? Mitra akan kembali ke akses terbatas.`);
  if (!confirmed) return;
  try {
    await api(`/api/admin/owner/resellers/${id}/revoke-full-access`, { method: "POST" });
    showToast(`Akses penuh "${name}" telah dicabut.`, "success");
    loadOwnerSettings().catch(() => {});
    loadFullAccessLogs().catch(() => {});
  } catch (err) {
    showToast(err.message, "error");
  }
};

window.denyFullAccess = async function(id, name) {
  const confirmed = await showConfirm(`Tolak permintaan akses penuh dari mitra "${name}"?`);
  if (!confirmed) return;
  try {
    await api(`/api/admin/owner/resellers/${id}/deny-full-access`, { method: "POST" });
    showToast(`Permintaan akses penuh "${name}" telah ditolak.`, "success");
    loadOwnerSettings().catch(() => {});
    loadFullAccessLogs().catch(() => {});
  } catch (err) {
    showToast(err.message, "error");
  }
};

// Load access logs for owner
async function loadFullAccessLogs() {
  if (adminRole !== "owner") return;
  try {
    const filterType = els.fullAccessLogFilter?.value || "";
    const search = els.fullAccessLogSearch?.value || "";
    const params = new URLSearchParams();
    if (filterType) params.set("type", filterType);
    if (search) params.set("search", search);
    params.set("limit", "100");

    const res = await api(`/api/admin/owner/full-access/logs?${params.toString()}`);
    if (!res.ok) return;

    const listEl = els.fullAccessLogList;
    if (!listEl) return;

    if (!res.entries || !res.entries.length) {
      listEl.innerHTML = `<div style="padding: 24px; text-align: center; color: var(--muted);">Belum ada log aktivitas akses penuh.</div>`;
      return;
    }

    const typeColors = {
      request: { bg: "rgba(251,191,36,0.15)", border: "rgba(251,191,36,0.4)", icon: "📩", label: "Permintaan", color: "#fbbf24" },
      grant: { bg: "rgba(52,211,153,0.15)", border: "rgba(52,211,153,0.4)", icon: "✅", label: "Disetujui", color: "#34d399" },
      revoke: { bg: "rgba(239,68,68,0.15)", border: "rgba(239,68,68,0.4)", icon: "🔒", label: "Dicabut", color: "#f87171" },
      deny: { bg: "rgba(156,163,175,0.15)", border: "rgba(156,163,175,0.4)", icon: "✕", label: "Ditolak", color: "#9ca3af" },
      access: { bg: "rgba(59,130,246,0.15)", border: "rgba(59,130,246,0.4)", icon: "📋", label: "Aktivitas", color: "#60a5fa" },
    };

    let html = "";
    for (const entry of res.entries) {
      const tc = typeColors[entry.type] || typeColors.access;
      const time = new Date(entry.timestamp).toLocaleString("id-ID");
      html += `
        <div style="padding: 8px 12px; border-bottom: 1px solid var(--border); border-left: 3px solid ${tc.border}; background: ${tc.bg}; margin-bottom: 1px;">
          <div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 4px;">
            <span style="font-weight: 600; color: ${tc.color}; font-size: 0.8rem;">${tc.icon} ${tc.label}</span>
            <span style="font-size: 0.7rem; color: var(--muted);">${time}</span>
          </div>
          <div style="font-size: 0.78rem; color: var(--text); margin-top: 2px;">${escapeHtml(entry.description || entry.action || "")}</div>
          <div style="font-size: 0.7rem; color: var(--muted); margin-top: 2px;">Oleh: ${escapeHtml(entry.actorName || "Unknown")}</div>
        </div>`;
    }
    listEl.innerHTML = html;
  } catch (err) {
    console.error("Gagal memuat log akses:", err);
  }
}

// Event: Refresh log button
if (els.fullAccessLogRefreshBtn) {
  els.fullAccessLogRefreshBtn.addEventListener("click", () => loadFullAccessLogs());
}

// Event: Log filter
if (els.fullAccessLogFilter) {
  els.fullAccessLogFilter.addEventListener("change", () => loadFullAccessLogs());
}
if (els.fullAccessLogSearch) {
  let logSearchTimeout;
  els.fullAccessLogSearch.addEventListener("input", () => {
    clearTimeout(logSearchTimeout);
    logSearchTimeout = setTimeout(() => loadFullAccessLogs(), 400);
  });
}

(async function init() {
  const saved = sessionStorage.getItem(ADMIN_KEY);
  const flashMsg = sessionStorage.getItem("login_flash_message");
  if (flashMsg) {
    setLoginStatus(flashMsg, "warn");
    sessionStorage.removeItem("login_flash_message");
  }
  if (saved) {
    const ok = await tryLogin(saved);
    if (!ok) sessionStorage.removeItem(ADMIN_KEY);
  }
  if (adminPass) {
    loadPoolSettings().catch(() => {});
    refreshMaintenanceStatus().catch(() => {});
    refreshPromoStatus().catch(() => {});
  }
  setInterval(() => { if (!els.adminScreen.hidden) refresh(); }, 30_000);
})();
