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"),
  tabBtnOwner: $("tab-btn-owner"),
  tabPanelPool: $("tab-panel-pool"),
  tabPanelArchive: $("tab-panel-archive"),
  tabPanelVoucher: $("tab-panel-voucher"),
  tabPanelTools: $("tab-panel-tools"),
  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"),
  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"),
  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"),
  editVchPricePaid: $("edit-vch-price-paid"),
  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"),
  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"),
  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"),
};

// ─── 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") {
  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);
  }, 4000);
}

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 showOwner = tab === "owner";
  els.tabPanelPool.hidden = !showPool;
  els.tabPanelArchive.hidden = !showArchive;
  els.tabPanelVoucher.hidden = !showVoucher;
  els.tabPanelTools.hidden = !showTools;
  if (els.tabPanelOwner) els.tabPanelOwner.hidden = !showOwner;
  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.tabBtnOwner) els.tabBtnOwner.classList.toggle("active", showOwner);

  if (showOwner) {
    loadOwnerSettings().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;

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;

    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));

    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");
  
  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.resellerInfoBar) els.resellerInfoBar.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") {
    if (addManualCard) addManualCard.style.display = "block";
    if (bulkImportCard) bulkImportCard.style.display = "block";
    
    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";
    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')}`;
      }
    }

    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";
  }

  const editPricePaidWrapper = document.getElementById("edit-vch-price-paid-wrapper");
  if (editPricePaidWrapper) {
    editPricePaidWrapper.style.display = adminRole === "mitra" ? "none" : "block";
  }
}

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");

  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));

  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;'}">
        <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.tabBtnOwner) els.tabBtnOwner.addEventListener("click", () => switchAdminTab("owner"));

// 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();
    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;
      await fetch("/api/admin/pool/settings", {
        method: "PUT",
        headers: buildAuthHeaders(),
        body: JSON.stringify({ maxRuns, monthlyCredits }),
      });
      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 (!confirm("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();
      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 (!confirm("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();
  }

  // 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("▶ Memulai pembuatan akun baru...", "info");
    await api("/api/admin/auto-token/run", { method: "POST", body: JSON.stringify({ force: true, mode: "create_only" }) });
  } catch (err) {
    appendLog(`❌ Gagal memulai bot: ${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");
    }
  });
}

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(`⏹️ Bot dihentikan: ${res.msg || "Selesai"}`, "warn");
    setBotStatus("idle");
  } catch (err) {
    appendLog(`❌ Gagal menghentikan bot: ${err.message}`, "error");
  } finally {
    els.botStopBtn.disabled = false;
    els.botStopBtn.textContent = "⏹️ Hentikan Bot";
  }
});

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;
  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>`;
      }
    }

    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>
        </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>
          ${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();
    }

    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");
  }
});

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 = prompt("PERINGATAN: Tindakan ini akan menghapus semua akun di Dashboard Archive secara permanen.\n\nMasukkan password admin untuk melanjutkan:");
  if (password === null) return; // User cancelled
  
  const correctPassword = sessionStorage.getItem(ADMIN_KEY) || adminPass;
  if (password !== correctPassword) {
    alert("Gagal: Password admin salah!");
    return;
  }
  
  if (!confirm("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",
    });
    alert(`Berhasil menghapus ${res.deleted} akun dari archive.`);
    refresh();
  } catch (err) {
    alert("Gagal menghapus archive: " + err.message);
  } finally {
    if (btn) { btn.disabled = false; btn.textContent = "🗑️ Hapus Semua Arsip"; }
  }
};

window.deleteAllPoolAccounts = async function() {
  const password = prompt("PERINGATAN: Tindakan ini akan menghapus SEMUA akun di Pool Akun secara permanen.\n\nMasukkan password admin untuk melanjutkan:");
  if (password === null) return;
  
  const correctPassword = sessionStorage.getItem(ADMIN_KEY) || adminPass;
  if (password !== correctPassword) {
    alert("Gagal: Password admin salah!");
    return;
  }
  
  if (!confirm("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",
    });
    alert(`Berhasil menghapus ${res.deleted} akun dari Pool.`);
    refresh();
  } catch (err) {
    alert("Gagal menghapus Pool: " + err.message);
  } 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" });
  }
});

// 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 || []);
  } 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;

    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;">
          <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>
          ${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'})">✏️</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) {
  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.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;

    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 })
      });
      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;
      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;

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

    const payload = { 
      name, 
      quota, 
      balance, 
      customResellerPrice, 
      customSrp, 
      customResellerVipPrice,
      customVipSrp,
      allowBot, 
      allowPool, 
      allowArchive 
    };
    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;
}

(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);
  }
  loadPoolSettings().catch(() => {});
  refreshMaintenanceStatus().catch(() => {});
  refreshPromoStatus().catch(() => {});
  setInterval(() => { if (!els.adminScreen.hidden) refresh(); }, 30_000);
})();
