// assets/js/wd.js
import { requireSession, apiFetch, brandDisplayName, getQueryParam } from "../app.js";

  // === BASE PANEL-API (subdomain terpisah) ===
  const PANEL_API_BASE = 'https://panel-api.tiaratt888.workers.dev';
  let PANEL_USER = 'admin';

  // Wrapper fetch khusus panel-api  (✅ kirim cookie JWT)
  async function panelApiFetch(path, options = {}) {
    const res = await fetch(`${PANEL_API_BASE}${path}`, {
      method: options.method || 'GET',
      credentials: 'include',
      headers: {
        'content-type': 'application/json',
        'X-Panel-User': PANEL_USER,
        ...(options.headers || {})
      },
      body: options.body
    });
    const json = await res.json().catch(() => ({}));
    if (!res.ok) throw Object.assign(new Error('HTTP ' + res.status), { response: json });
    return json;
  }

  async function logChatToDB(_dir, _payload = {}) { return; }

  // ===== STATE =====
  const activeBrand = (getQueryParam("brand") || "tiara").toLowerCase();
  const activeChannel = "wd";
  const REQUIRED_SCOPE_PAGE = "proses";
  const brandLogoMap = {
    tiara: "assets/img/tiaratoto.png",
    tts:  "assets/img/totosakti.png",
    ttm:  "assets/img/totomantap.png", // pastikan file ini ada
  };
  const brandBadgeText = { tiara: "TIARATOTO", tts: "TOTOSAKTI", ttm: "TOTOMANTAP" }[activeBrand] || "BRAND";

  // ===== PERSISTENCE (localStorage) =====
  const CHAT_MAX_ITEMS = 200;
  const chatKey = () => `panelchat:${activeBrand}:${activeChannel}:${PANEL_USER || 'guest'}`;
  const draftKey = () => `paneldraft:${activeBrand}:${activeChannel}:${PANEL_USER || 'guest'}`;

  function loadChatLog() {
    try { return JSON.parse(localStorage.getItem(chatKey()) || "[]"); }
    catch { return []; }
  }
  function saveChatLog(items) {
    const sliced = items.slice(-CHAT_MAX_ITEMS);
    localStorage.setItem(chatKey(), JSON.stringify(sliced));
  }
  function appendChatEntry(entry) {
    const items = loadChatLog();
    items.push({ ts: Date.now(), ...entry });
    saveChatLog(items);
  }
  function clearChatLog() { localStorage.removeItem(chatKey()); }

  // ===== DOM REFS =====
  const els = {
    desktopLogo: document.getElementById("desktopBrandLogo"),
    mobileLogo: document.getElementById("mobileBrandLogo"),
    sideMenuDesktop: document.getElementById("sideMenuDesktop"),
    sideMenuMobile: document.getElementById("sideMenuMobile"),
    brandLabel: document.getElementById("brandLabel"),
    brandDropdown: document.getElementById("brandDropdown"),
    brandBtn: document.getElementById("brandBtn"),
    userBtn: document.getElementById("userMenuBtn"),
    userDropdown: document.getElementById("userDropdown"),
    topUser: document.getElementById("topUser"),
    themeToggleBtn: document.getElementById("themeToggleBtn"),
    ddThemeText: document.getElementById("ddThemeText"),
    ddLogoutText: document.getElementById("ddLogoutText"),
    logoutBtn: document.getElementById("logoutBtn"),
    hamburgerBtn: document.getElementById("hamburgerBtn"),
    mobileSidebar: document.getElementById("mobileSidebar"),
    closeSidebarBtn: document.getElementById("closeSidebarBtn"),
    sidebarOverlay: document.getElementById("sidebarOverlay"),
    pageTitle: document.getElementById("pageTitle"),
    brandBadge: document.getElementById("brandBadge"),
    pageDesc: document.getElementById("pageDesc"),
    chatList: document.getElementById("chatList"),
    chatScroll: document.getElementById("chatScroll"),
    chatInput: document.getElementById("chatInput"),
    sendBtn: document.getElementById("sendBtn"),
    pasteBtn: document.getElementById("pasteBtn"),
    sheetSelect: document.getElementById("sheetSelect"),
    refreshSheets: document.getElementById("refreshSheets"),
    sheetStatus: document.getElementById("sheetStatus"),
    parseHint: document.getElementById("parseHint"),
    composerNote: document.getElementById("composerNote"),
    forbiddenOverlay: document.getElementById("forbiddenOverlay"),
    forbiddenTitle: document.getElementById("forbiddenTitle"),
    forbiddenDesc: document.getElementById("forbiddenDesc"),
    goHomeBtnText: document.getElementById("goHomeBtnText"),
    clearHistory: document.getElementById("clearHistory"),

    // Filter Sheet (gear)
    sheetFilterWrap: document.getElementById("sheetFilterWrap"),
    sheetFilterBtn: document.getElementById("sheetFilterBtn"),
    sheetFilterDropdown: document.getElementById("sheetFilterDropdown"),
    sheetFilterList: document.getElementById("sheetFilterList"),
    sheetFilterCount: document.getElementById("sheetFilterCount"),
    sheetFilterSave: document.getElementById("sheetFilterSave"),

    // Quick Nav (HP) - ✅ ditambah (SAMA bank.html)
    quickNavBtn: document.getElementById("quickNavBtn"),
    quickNavPanel: document.getElementById("quickNavPanel"),
    qnavBank: document.getElementById("qnavBank"),
    qnavEwallet: document.getElementById("qnavEwallet"),
    qnavPulsa: document.getElementById("qnavPulsa"),
    qnavWd: document.getElementById("qnavWd"),
  };

  // ===== QUICK NAV (HP) - ✅ ditambah (SAMA bank.html) =====
  function setQuickNavVisible(show) {
    if (!els.quickNavBtn) return;
    els.quickNavBtn.classList.toggle("hidden", !show);
    if (els.quickNavPanel) els.quickNavPanel.classList.add("hidden");
  }

  function setupQuickNav() {
    if (!els.quickNavBtn || !els.quickNavPanel) return;

    // inject link dengan brand aktif
    const qs = `?brand=${encodeURIComponent(activeBrand)}`;
    if (els.qnavBank) els.qnavBank.href = `bank.html${qs}`;
    if (els.qnavEwallet) els.qnavEwallet.href = `ewallet.html${qs}`;
    if (els.qnavPulsa) els.qnavPulsa.href = `pulsa.html${qs}`;
    if (els.qnavWd) els.qnavWd.href = `wd.html${qs}`;

    // highlight halaman aktif
    const map = { bank: els.qnavBank, ewallet: els.qnavEwallet, pulsa: els.qnavPulsa, wd: els.qnavWd };
    Object.entries(map).forEach(([ch, el]) => {
      if (!el) return;
      const active = (ch === activeChannel);
      el.classList.toggle("bg-blue-600", active);
      el.classList.toggle("text-white", active);
      el.classList.toggle("border-blue-600", active);
      el.classList.toggle("dark:border-blue-500", active);
    });

    // toggle panel
    els.quickNavBtn.addEventListener("click", (e) => {
      e.stopPropagation();
      els.quickNavPanel.classList.toggle("hidden");
    });
    els.quickNavPanel.addEventListener("click", (e) => e.stopPropagation());

    // klik luar / ESC untuk tutup
    document.addEventListener("click", () => {
      if (els.quickNavPanel && !els.quickNavPanel.classList.contains("hidden")) {
        els.quickNavPanel.classList.add("hidden");
      }
    });
    document.addEventListener("keydown", (e) => {
      if (e.key === "Escape" && els.quickNavPanel) els.quickNavPanel.classList.add("hidden");
    });
  }

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

  function wibStamp(ts = null) {
    const d = ts ? new Date(ts) : new Date();
    const fmt = new Intl.DateTimeFormat('id-ID', {
      timeZone: 'Asia/Jakarta',
      hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false
    });
    return fmt.format(d);
  }

  let growRAF = 0;
  function autoGrowSmooth(el) {
    if (!el) return;
    const MIN = 44, MAX = 224;
    const start = el.offsetHeight;
    el.style.height = 'auto';
    let target = Math.max(Math.min(el.scrollHeight, MAX), MIN);
    el.style.height = start + 'px';
    if (growRAF) cancelAnimationFrame(growRAF);
    growRAF = requestAnimationFrame(() => {
      el.style.height = target + 'px';
      const needScroll = el.scrollHeight > MAX;
      const currOverflow = el.style.overflowY || '';
      if (needScroll && currOverflow !== 'auto') el.style.overflowY = 'auto';
      else if (!needScroll && currOverflow !== 'hidden') el.style.overflowY = 'hidden';
    });
  }

  function resetComposerHeight(el) {
    if (!el) return;
    const MIN = 44;
    const start = el.offsetHeight;
    el.style.height = start + 'px';
    requestAnimationFrame(() => {
      el.value = '';
      el.style.height = MIN + 'px';
      el.style.overflowY = 'hidden';
      el.scrollTop = 0;
    });
  }

  function scrollChatToBottom() {
    if (!els.chatScroll) return;
    const el = els.chatScroll;
    const prev = el.style.scrollBehavior;
    el.style.scrollBehavior = 'auto';
    el.scrollTop = el.scrollHeight;
    requestAnimationFrame(() => {
      el.scrollTop = el.scrollHeight;
      el.style.scrollBehavior = prev || '';
    });
  }

  // ===== CLOCK CARD + UPDATE =====
  function sidebarClockCard(prefix) {
    return `
      <div class="mb-4">
        <div class="rounded-lg border border-slate-300 dark:border-[#3f3f46]
                    bg-slate-50 dark:bg-[#2a2a2a]
                    text-[12px] leading-tight text-slate-700 dark:text-slate-200 p-3">
          <div class="grid grid-cols-[max-content_1ch_1fr] items-baseline gap-x-2 gap-y-1">
            <div class="text-slate-500 dark:text-slate-400 font-medium">Tanggal</div>
            <div class="text-slate-500 dark:text-slate-400">:</div>
            <div id="sidebarDate${prefix}" class="font-semibold text-slate-800 dark:text-slate-100">-</div>

            <div class="text-slate-500 dark:text-slate-400 font-medium">Waktu</div>
            <div class="text-slate-500 dark:text-slate-400">:</div>
            <div id="sidebarTime${prefix}" class="font-semibold text-slate-800 dark:text-slate-100">-</div>
          </div>
        </div>
      </div>
    `;
  }

  function updateSidebarClock() {
    const now = new Date();
    const weekdayId = new Intl.DateTimeFormat('id-ID', { timeZone: 'Asia/Jakarta', weekday: 'long' }).format(now);
    const parts = new Intl.DateTimeFormat('en-US', {
      timeZone: 'Asia/Jakarta',
      year: 'numeric', month: 'numeric', day: '2-digit',
      hour: '2-digit', minute: '2-digit', second: '2-digit',
      hour12: false
    }).formatToParts(now);

    let dd = "", mm = "", yyyy = "", hh = "", mi = "", ss = "";
    parts.forEach(p => {
      if (p.type === "day") dd = p.value;
      if (p.type === "month") mm = p.value;
      if (p.type === "year") yyyy = p.value;
      if (p.type === "hour") hh = p.value;
      if (p.type === "minute") mi = p.value;
      if (p.type === "second") ss = p.value;
    });

    const bulanShort = ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des"];
    const tanggalStr = `${weekdayId}, ${dd} ${bulanShort[parseInt(mm, 10) - 1] || mm} ${yyyy}`;
    const waktuStr = `${hh}:${mi}:${ss}`;

    ["Desktop", "Mobile"].forEach(prefix => {
      const d = document.getElementById("sidebarDate" + prefix);
      const t = document.getElementById("sidebarTime" + prefix);
      if (d) d.textContent = tanggalStr;
      if (t) t.textContent = waktuStr;
    });
  }

  // ===== ICONS =====
  function iconSVG(name, highlight = false) {
    const base = highlight ? "text-blue-500 dark:text-blue-400" : "text-slate-500 dark:text-slate-400";
    if (name === "home") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M3 12L12 3l9 9"/><path d="M9 21V12h6v9"/></svg></span>`;
    if (name === "sheets") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="3" y1="10" x2="21" y2="10"/><line x1="9" y1="4" x2="9" y2="22"/></svg></span>`;
    if (name === "brand") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><circle cx="19" cy="12" r="3"/><circle cx="5" cy="12" r="3"/></svg></span>`;
    if (name === "profile") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span>`;
    if (name === "chat") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M21 15a4 4 0 0 1-4 4H7l-4 4V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4z"/></svg></span>`;
    if (name === "users") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M17 21v-2a4 4 0 0 0-4-4H7a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg></span>`;
    if (name === "report") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M9 3h6a2 2 0 0 1 2 2v16l-5-3-5 3V5a2 2 0 0 1 2-2z"/></svg></span>`;
    if (name === "zap") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><polyline points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg></span>`;

    // ✅ NEW: icon Notifikasi (Bank & Ewallet)
    if (name === "bank") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M3 10h18"/><path d="M5 10v10"/><path d="M9 10v10"/><path d="M15 10v10"/><path d="M19 10v10"/><path d="M4 20h16"/><path d="M12 3l9 5H3l9-5z"/></svg></span>`;
    if (name === "wallet") return `<span class="${base}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v3"/><path d="M21 12h-7a2 2 0 0 0 0 4h7v-4z"/><circle cx="16" cy="14" r="1"/></svg></span>`;

    return "";
  }

  // ===== SIDEBAR MAP =====
  const brandMap = {
    tiara: {
      badge: "TIARATOTO",
      sections: [
        { label: "Dashboard", items: [ { text: "Dashboard", href: `index.html?brand=tiara`, icon: "home", active: false } ] },
        { label: null, brandBadge: "TIARATOTO", items: [
          { text: "Global Sheets", href: `global.html?brand=tiara`, icon: "sheets", active: false },
          { text: "Brand Meta", href: `brand.html?brand=tiara`, icon: "brand", active: false },
          { text: "Profiles", href: null, icon: "profile", active: false, submenu: [
            { text: "Edit Bank", channel: "bank" },
            { text: "Edit Ewallet", channel: "ewallet" },
            { text: "Edit Pulsa", channel: "pulsa" },
            { text: "Edit Withdraw", channel: "wd" },
          ]},
        ]},
        { label: "Proses", items: [
          { text: "Catat Bank", href: `bank.html?brand=tiara`, icon: "chat", active: false },
          { text: "Catat Ewallet", href: `ewallet.html?brand=tiara`, icon: "chat", active: false },
          { text: "Catat Pulsa", href: `pulsa.html?brand=tiara`, icon: "chat", active: false },
          { text: "Catat Withdraw", href: `wd.html?brand=tiara`, icon: "chat", active: true },
        ]},

        // ✅ NEW: NOTIFIKASI
        { label: "Notifikasi", items: [
          { text: "Bank", href: `notifbank.html?brand=tiara`, icon: "bank", active: false },
          { text: "Ewallet", href: `notifewallet.html?brand=tiara`, icon: "wallet", active: false },
        ]},

        { label: "Laporan", items: [
          { text: "Pendingan", href: `pendingan.html?brand=tiara`, icon: "report", active: false },
          { text: "Mistake", href: `mistake.html?brand=tiara`, icon: "report", active: false },
        ]},
        { label: "Auto Withdraw", items: [ { text: "Withdraw", href: `withdraw-awd.html?brand=tiara`, icon: "zap", active: false } ] },
        { label: "Admin", items: [ { text: "Users", href: `users.html?brand=tiara`, icon: "users", active: false, requireSuperadmin: true } ] },
      ],
    },
    tts: {
      badge: "TOTOSAKTI",
      sections: [
        { label: "Dashboard", items: [ { text: "Dashboard", href: `index.html?brand=tts`, icon: "home", active: false } ] },
        { label: null, brandBadge: "TOTOSAKTI", items: [
          { text: "Global Sheets", href: `global.html?brand=tts`, icon: "sheets", active: false },
          { text: "Brand Meta", href: `brand.html?brand=tts`, icon: "brand", active: false },
          { text: "Profiles", href: null, icon: "profile", active: false, submenu: [
            { text: "Edit Bank", channel: "bank" },
            { text: "Edit Ewallet", channel: "ewallet" },
            { text: "Edit Pulsa", channel: "pulsa" },
            { text: "Edit Withdraw", channel: "wd" },
          ]},
        ]},
        { label: "Proses", items: [
          { text: "Catat Bank", href: `bank.html?brand=tts`, icon: "chat", active: false },
          { text: "Catat Ewallet", href: `ewallet.html?brand=tts`, icon: "chat", active: false },
          { text: "Catat Pulsa", href: `pulsa.html?brand=tts`, icon: "chat", active: false },
          { text: "Catat Withdraw", href: `wd.html?brand=tts`, icon: "chat", active: true },
        ]},

        // ✅ NEW: NOTIFIKASI
        { label: "Notifikasi", items: [
          { text: "Bank", href: `notifbank.html?brand=tts`, icon: "bank", active: false },
          { text: "Ewallet", href: `notifewallet.html?brand=tts`, icon: "wallet", active: false },
        ]},

        { label: "Laporan", items: [
          { text: "Pendingan", href: `pendingan.html?brand=tts`, icon: "report", active: false },
          { text: "Mistake", href: `mistake.html?brand=tts`, icon: "report", active: false },
        ]},
        { label: "Auto Withdraw", items: [ { text: "Withdraw", href: `withdraw-awd.html?brand=tts`, icon: "zap", active: false } ] },
        { label: "Admin", items: [ { text: "Users", href: `users.html?brand=tts`, icon: "users", active: false, requireSuperadmin: true } ] },
      ],
    },
    ttm: {
      badge: "TOTOMANTAP",
      sections: [
        { label: "Dashboard", items: [
          { text: "Dashboard", href: `index.html?brand=ttm`, icon: "home", active: false }
        ]},
        { label: null, brandBadge: "TOTOMANTAP", items: [
          { text: "Global Sheets", href: `global.html?brand=ttm`, icon: "sheets", active: false },
          { text: "Brand Meta", href: `brand.html?brand=ttm`, icon: "brand", active: false },
          { text: "Profiles", href: null, icon: "profile", active: false, submenu: [
            { text: "Edit Bank", channel: "bank" },
            { text: "Edit Ewallet", channel: "ewallet" },
            { text: "Edit Pulsa", channel: "pulsa" },
            { text: "Edit Withdraw", channel: "wd" },
          ]},
        ]},
        { label: "Proses", items: [
          { text: "Catat Bank", href: `bank.html?brand=ttm`, icon: "chat", active: false },
          { text: "Catat Ewallet", href: `ewallet.html?brand=ttm`, icon: "chat", active: false },
          { text: "Catat Pulsa", href: `pulsa.html?brand=ttm`, icon: "chat", active: false },
          { text: "Catat Withdraw", href: `wd.html?brand=ttm`, icon: "chat", active: true },
        ]},

        // ✅ NEW: NOTIFIKASI
        { label: "Notifikasi", items: [
          { text: "Bank", href: `notifbank.html?brand=ttm`, icon: "bank", active: false },
          { text: "Ewallet", href: `notifewallet.html?brand=ttm`, icon: "wallet", active: false },
        ]},

        { label: "Laporan", items: [
          { text: "Pendingan", href: `pendingan.html?brand=ttm`, icon: "report", active: false },
          { text: "Mistake", href: `mistake.html?brand=ttm`, icon: "report", active: false },
        ]},
        { label: "Auto Withdraw", items: [
          { text: "Withdraw", href: `withdraw-awd.html?brand=ttm`, icon: "zap", active: false }
        ]},
        { label: "Admin", items: [
          { text: "Users", href: `users.html?brand=ttm`, icon: "users", active: false, requireSuperadmin: true }
        ]},
      ],
    },
  };

  // ===== RBAC helpers =====
  function normalizeScopes(src) {
    if (Array.isArray(src)) return src.map(String).map(s => s.trim().toLowerCase()).filter(Boolean);
    if (src && typeof src === "object") return Object.keys(src).filter(k => !!src[k]).map(k => k.toLowerCase());
    if (typeof src === "string") return src.split(/[,\s]+/).map(s => s.trim().toLowerCase()).filter(Boolean);
    return [];
  }

  function scopeForHref(href) {
    if (!href) return null;

    // ✅ NEW: scope Notifikasi
    if (href.includes("notifbank") || href.includes("notifewallet")) return "notifikasi";

    if (href.includes("withdraw-awd")) return "autowd";
    if (href.includes("pendingan") || href.includes("mistake")) return "laporan";
    if (href.includes("global.html") || href.includes("brand.html") || href.includes("profile-edit.html")) return "brand";
    if (href.includes("bank.html") || href.includes("ewallet.html") || href.includes("pulsa.html") || href.includes("wd.html")) return "proses";
    return null;
  }

  function hasScope(name, { isSuperadmin, scopes }) {
    if (isSuperadmin) return true;
    name = String(name || "").toLowerCase();
    return scopes.includes(name);
  }

  function renderSidebar(brandKey, prefix, opts = {}) {
    const isSuperadmin = !!opts.isSuperadmin;
    const scopes = opts.scopes || [];
    const cfg = brandMap[brandKey] || brandMap["tiara"];
    const parentActiveCls = "bg-blue-50 text-blue-600 border-blue-200 dark:bg-blue-950/40 dark:text-blue-400 dark:border-blue-800";
    const parentNormalCls = "hover:bg-slate-100 hover:text-blue-600 border-transparent text-slate-700 dark:text-slate-200 dark:hover:bg-[#2a2a2a] dark:hover:text-blue-400";

    let html = sidebarClockCard(prefix);

    cfg.sections.forEach(section => {
      const visibleItems = (section.items || []).filter(item => {
        if (item.requireSuperadmin && !isSuperadmin) return false;
        if (item.icon === "profile") return hasScope("brand", { isSuperadmin, scopes });
        const needed = scopeForHref(item.href);
        if (!needed) return true;
        return hasScope(needed, { isSuperadmin, scopes });
      });

      if (!visibleItems.length) return;

      const sectionTitle = section.label ? section.label.toUpperCase() : section.brandBadge;
      html += `
        <div class="mb-4">
          <div class="text-[11px] uppercase font-semibold text-slate-400 dark:text-slate-500 tracking-wide mb-2">${sectionTitle}</div>
          <ul class="space-y-1">
      `;

      visibleItems.forEach(item => {
        if (item.icon === "profile") {
          const btnCls = parentNormalCls;
          html += `
            <li>
              <button id="profilesToggle${prefix}"
                class="w-full flex items-center justify-between px-3 py-2 rounded-md font-medium border ${btnCls}">
                <span class="flex items-center gap-2">
                  ${iconSVG(item.icon, false)}
                  <span>${item.text}</span>
                </span>
                <span class="text-slate-500 dark:text-slate-400">
                  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"
                    fill="none" stroke="currentColor" stroke-width="1.5"
                    stroke-linecap="round" stroke-linejoin="round"
                    viewBox="0 0 24 24" class="transition-transform" data-chevron>
                    <polyline points="6 9 12 15 18 9"/>
                  </svg>
                </span>
              </button>
              <ul id="profilesSub${prefix}" class="mt-1 ml-6 space-y-1 hidden">
                ${(item.submenu || []).map(sub => {
                  const subCls = parentNormalCls;
                  return `
                    <li>
                      <a href="profile-edit.html?brand=${brandKey}&channel=${sub.channel}"
                        class="flex items-center gap-2 px-3 py-2 rounded-md font-medium border text-[12px] leading-tight ${subCls}">
                        <span class="w-2 h-2 rounded-full bg-current"></span>
                        <span>${sub.text}</span>
                      </a>
                    </li>
                  `;
                }).join("")}
              </ul>
            </li>
          `;
        } else {
          const active = !!item.active;
          const linkCls = active ? parentActiveCls : parentNormalCls;
          html += `
            <li>
              <a href="${item.href}"
                 class="flex items-center gap-2 px-3 py-2 rounded-md font-medium border ${linkCls}">
                ${iconSVG(item.icon, active)}
                <span>${item.text}</span>
              </a>
            </li>
          `;
        }
      });

      html += `</ul></div>`;
    });

    return html;
  }

  function attachSidebarToggle(prefix) {
    const btn = document.getElementById("profilesToggle" + prefix);
    const sub = document.getElementById("profilesSub" + prefix);
    if (!btn || !sub) return;
    btn.addEventListener("click", () => {
      sub.classList.toggle("hidden");
      const chev = btn.querySelector("[data-chevron]");
      if (chev) chev.classList.toggle("rotate-180");
    });
  }

  function renderUserBubble(text, ts) {
    const html = `
      <div class="flex justify-end">
        <div class="max-w-[80%] rounded-2xl rounded-br-sm border border-blue-200 dark:border-blue-900 bg-blue-50 dark:bg-blue-950/30 px-3 py-2 text-[14px] leading-relaxed">
          <div class="whitespace-pre-wrap">${escapeHTML(text)}</div>
          <div class="text-[11px] text-slate-500 dark:text-slate-400 mt-1 text-right">${wibStamp(ts)}</div>
        </div>
      </div>`;
    els.chatList.insertAdjacentHTML("beforeend", html);
    scrollChatToBottom();
  }

  function renderBotBubble(htmlText, ts) {
    const html = `
      <div class="flex justify-start">
        <div class="max-w-[80%] rounded-2xl rounded-bl-sm border border-slate-200 dark:border-[#2a2a2a] bg-white dark:bg-[#121212] px-3 py-2 text-[14px] leading-relaxed shadow-sm">
          ${htmlText}
          <div class="text-[11px] text-slate-500 dark:text-slate-400 mt-1">${wibStamp(ts)}</div>
        </div>
      </div>`;
    els.chatList.insertAdjacentHTML("beforeend", html);
    scrollChatToBottom();
  }

  function addBotBubble(htmlText) {
    const ts = Date.now();
    renderBotBubble(htmlText, ts);
    appendChatEntry({ from: "bot", html: htmlText, ts });
    logChatToDB("bot", { html: htmlText });
  }

  // ===== PARSER HINT (WD) =====
  function looksLike8Lines(text) {
    const lines = (text || "").split("\n").map(s => s.trim()).filter(Boolean);
    return lines.length === 8;
  }
  function setParseHint(text) {
    if (!els.parseHint) return;
    els.parseHint.textContent = looksLike8Lines(text) ? "Terdeteksi: WD 8 baris (siap kirim)." : "";
  }

  // ===== SHEETS LOADER =====
  const LS_SHEET_KEY = (brand) => `panel:last_sheet:${brand}:wd`;

  // ===== FILTER SHEETS (HANYA UI) =====
  const sheetFilterKey = () => `panel:sheet_hidden:${activeBrand}:${activeChannel}:${PANEL_USER || "guest"}`;
  let allowedSheetsCache = [];

  function loadHiddenSheets() {
    try {
      const raw = localStorage.getItem(sheetFilterKey());
      const arr = raw ? JSON.parse(raw) : [];
      return Array.isArray(arr) ? arr.map(String) : [];
    } catch {
      return [];
    }
  }

  function buildSheetFilterUI(allowed) {
    if (!els.sheetFilterList) return;

    const hidden = new Set(loadHiddenSheets());
    allowedSheetsCache = Array.isArray(allowed) ? allowed.slice() : [];

    if (!allowedSheetsCache.length) {
      els.sheetFilterList.innerHTML = `<div class="text-[11px] text-slate-500 dark:text-slate-400 py-2">(Tidak ada sheet)</div>`;
      if (els.sheetFilterCount) els.sheetFilterCount.textContent = `0/0 aktif`;
      return;
    }

    els.sheetFilterList.innerHTML = allowedSheetsCache.map((s) => {
      const enc = encodeURIComponent(s);
      const checked = !hidden.has(s);
      return `
        <label class="flex items-center gap-2 px-2 py-1 rounded-md hover:bg-slate-100 dark:hover:bg-[#2a2a2a] cursor-pointer">
          <input type="checkbox" class="h-4 w-4 rounded border-slate-300 dark:border-[#3f3f46]"
            data-sheet="${enc}" ${checked ? "checked" : ""}/>
          <span class="text-[12px] text-slate-800 dark:text-slate-100">${escapeHTML(s)}</span>
        </label>
      `;
    }).join("");

    els.sheetFilterList.querySelectorAll('input[type="checkbox"][data-sheet]').forEach(cb => {
      cb.addEventListener("change", updateSheetFilterCount);
    });
    updateSheetFilterCount();
  }

  function updateSheetFilterCount() {
    if (!els.sheetFilterCount || !els.sheetFilterList) return;
    const boxes = Array.from(els.sheetFilterList.querySelectorAll('input[type="checkbox"][data-sheet]'));
    const total = boxes.length;
    const on = boxes.filter(b => b.checked).length;
    els.sheetFilterCount.textContent = `${on}/${total} aktif`;
  }

  function applySheetVisibilityToSelect(allowed) {
    const hidden = new Set(loadHiddenSheets());
    const visible = (allowed || []).filter(s => !hidden.has(s));

    if (!visible.length) {
      els.sheetSelect.innerHTML = `<option value="">(Tidak ada sheet tampil)</option>`;
      if (els.sheetStatus) els.sheetStatus.textContent = "Tidak ada sheet tampil (atur di Filter).";
      return;
    }

    const last = localStorage.getItem(LS_SHEET_KEY(activeBrand)) || "";
    const selected = (last && visible.includes(last)) ? last : visible[0];

    els.sheetSelect.innerHTML = visible.map(s => `<option ${s === selected ? 'selected' : ''}>${escapeHTML(s)}</option>`).join("");
    if (els.sheetStatus) els.sheetStatus.textContent = `Sheet aktif: ${els.sheetSelect.value || "-"}`;

    if (selected && selected !== last) localStorage.setItem(LS_SHEET_KEY(activeBrand), selected);
  }

  function saveSheetFilterFromUI() {
    if (!els.sheetFilterList) return;
    const boxes = Array.from(els.sheetFilterList.querySelectorAll('input[type="checkbox"][data-sheet]'));
    const hidden = [];
    boxes.forEach(b => {
      const name = decodeURIComponent(b.dataset.sheet || "");
      if (!b.checked) hidden.push(name);
    });
    localStorage.setItem(sheetFilterKey(), JSON.stringify(hidden));
  }

  async function loadSheets() {
    els.sheetSelect.innerHTML = `<option>(Memuat...)</option>`;
    try {
      const data = await panelApiFetch(`/api/panelcfg/${activeBrand}/wd`);
      const allowed = data?.allowed_sheets || data?.cfg?.allowed_sheets || [];
      allowedSheetsCache = Array.isArray(allowed) ? allowed.slice() : [];
      buildSheetFilterUI(allowedSheetsCache);

      if (!allowedSheetsCache.length) {
        els.sheetSelect.innerHTML = `<option value="">(Tidak ada sheet)</option>`;
        if (els.sheetStatus) els.sheetStatus.textContent = "Tidak ada sheet yang diizinkan.";
        return;
      }
      applySheetVisibilityToSelect(allowedSheetsCache);
    } catch (e) {
      els.sheetSelect.innerHTML = `<option value="">(Gagal memuat)</option>`;
      if (els.sheetStatus) els.sheetStatus.textContent = "Gagal memuat sheet (cek API).";
      buildSheetFilterUI([]);
    }
  }

  // ===== SEND HANDLER =====
  async function doSend() {
    const text = els.chatInput.value;
    const sheet = els.sheetSelect.value;

    if (!sheet) {
      renderBotBubble(`<div class="text-red-600 dark:text-red-400">Pilih sheet dulu ya.</div>`, Date.now());
      return;
    }
    if (!text.trim()) {
      renderBotBubble(`<div class="text-red-600 dark:text-red-400">Teks masih kosong.</div>`, Date.now());
      return;
    }

    const sentTs = Date.now();
    const userTextSent = text;
    renderUserBubble(userTextSent, sentTs);

    const body = {
      kind: "raw_text",
      sheet,
      idempotency_key: (window.crypto && crypto.randomUUID ? crypto.randomUUID() : String(Math.random()).slice(2)),
      payload: { raw_text: userTextSent }
    };

    localStorage.setItem(LS_SHEET_KEY(activeBrand), sheet);
    if (els.sheetStatus) els.sheetStatus.textContent = `Sheet aktif: ${sheet}`;
    resetComposerHeight(els.chatInput);
    setParseHint("");
    localStorage.removeItem(draftKey());

    const prev = els.sendBtn.textContent;
    els.sendBtn.textContent = "Mengirim...";
    els.sendBtn.disabled = true;

    try {
      const res = await panelApiFetch(`/api/catat/${activeBrand}/wd`, { method: "POST", body: JSON.stringify(body) });

      if (res?.ok) {
        appendChatEntry({ from: "user", text: userTextSent, ts: sentTs });
        const note = res?.message ? escapeHTML(res.message) : `✅ WD dicatat di DOC "${escapeHTML(sheet)}"`;
        addBotBubble(`<div>${note}</div>`);
      } else {
        const errKey = (res && res.error) || "unknown_error";
        const msgMap = {
          duplicate: "⚠️ DOUBLE CATAT !! CEK LAGI....",
          sheet_not_allowed: "Sheet tidak diizinkan.",
          invalid_format: 'Format tidak dikenali. Tempel WD 8 baris format lama.',
          no_sheet_mapping: "Sheet belum dipetakan di Global Sheets.",
          channel_not_implemented: "Fitur withdraw belum diaktifkan di API (501). Update worker.js.",
        };
        const msg = msgMap[errKey] || "Gagal mencatat.";
        renderBotBubble(`<div class="text-red-600 dark:text-red-400">${escapeHTML(msg)}</div>`, Date.now());
        els.chatInput.focus();
      }
    } catch (err) {
      const statusText = (err && err.message) || "";
      const apiErr = (err && err.response && err.response.error) || "";
      const errKind = (err && err.response && err.response.kind) || "";
      const detail = (err && err.response && err.response.detail) || "";

      const msgMap = {
        duplicate: "⚠️ DOUBLE CATAT !! CEK LAGI....",
        sheet_not_allowed: "Sheet tidak diizinkan.",
        invalid_format: 'Format tidak dikenali. Tempel WD 8 baris format lama.',
        no_sheet_mapping: "Sheet belum dipetakan di Global Sheets.",
        channel_not_implemented: "Fitur withdraw belum diaktifkan di API (501). Update worker.js.",
      };

      let msg = msgMap[apiErr];
      if (!msg && apiErr === "duplicate" && errKind === "idempotency") msg = "⚠️ DOUBLE CATAT !! CEK LAGI....";
      if (!msg && typeof apiErr === "string" && apiErr.trim()) {
        msg = apiErr;
        if (detail && typeof detail === "string") msg += `\n${detail}`;
      }
      if (!msg) {
        msg =
          statusText.startsWith("HTTP 4") ? "❌ Permintaan tidak valid." :
          statusText.startsWith("HTTP 5") ? "❌ Server bermasalah." :
          "❌ Gagal terhubung ke API.";
      }
      renderBotBubble(`<div class="text-red-600 dark:text-red-400" style="white-space:pre-line">${escapeHTML(msg)}</div>`, Date.now());
      els.chatInput.focus();
    } finally {
      els.sendBtn.textContent = prev;
      els.sendBtn.disabled = false;
    }
  }

  // ===== APPLY STATIC =====
  function applyStatic() {
    if (els.brandLabel) els.brandLabel.textContent = brandBadgeText;
    if (els.brandBadge) els.brandBadge.textContent = brandBadgeText;
    if (els.pageTitle) els.pageTitle.textContent = "Catat Withdraw";
    if (els.pageDesc) els.pageDesc.textContent = "Input Proses langsung ke Google Sheet untuk brand " + brandDisplayName(activeBrand) + ".";
    const logoSrc = brandLogoMap[activeBrand] || brandLogoMap.tiara;
    if (els.desktopLogo) { els.desktopLogo.src = logoSrc; els.desktopLogo.alt = brandBadgeText; }
    if (els.mobileLogo) { els.mobileLogo.src = logoSrc; els.mobileLogo.alt = brandBadgeText; }

    if (els.ddThemeText) els.ddThemeText.textContent = "Tema";
    if (els.ddLogoutText) els.ddLogoutText.textContent = "Keluar";

    if (els.brandBtn) {
      els.brandBtn.addEventListener("click", (e) => {
        e.stopPropagation();
        els.brandDropdown.classList.toggle("hidden");
        if (!els.userDropdown.classList.contains("hidden")) els.userDropdown.classList.add("hidden");
        if (els.sheetFilterDropdown && !els.sheetFilterDropdown.classList.contains("hidden")) els.sheetFilterDropdown.classList.add("hidden");
        if (els.quickNavPanel && !els.quickNavPanel.classList.contains("hidden")) els.quickNavPanel.classList.add("hidden");
      });
    }

    if (els.userBtn) {
      els.userBtn.addEventListener("click", (e) => {
        e.stopPropagation();
        els.userDropdown.classList.toggle("hidden");
        if (!els.brandDropdown.classList.contains("hidden")) els.brandDropdown.classList.add("hidden");
        if (els.sheetFilterDropdown && !els.sheetFilterDropdown.classList.contains("hidden")) els.sheetFilterDropdown.classList.add("hidden");
        if (els.quickNavPanel && !els.quickNavPanel.classList.contains("hidden")) els.quickNavPanel.classList.add("hidden");
      });
    }

    if (els.sheetFilterBtn) {
      els.sheetFilterBtn.addEventListener("click", (e) => {
        e.stopPropagation();
        if (els.sheetFilterDropdown) els.sheetFilterDropdown.classList.toggle("hidden");
        if (!els.brandDropdown.classList.contains("hidden")) els.brandDropdown.classList.add("hidden");
        if (!els.userDropdown.classList.contains("hidden")) els.userDropdown.classList.add("hidden");
        if (els.quickNavPanel && !els.quickNavPanel.classList.contains("hidden")) els.quickNavPanel.classList.add("hidden");
      });
    }
    if (els.sheetFilterDropdown) els.sheetFilterDropdown.addEventListener("click", (e) => e.stopPropagation());
    if (els.sheetFilterSave) {
      els.sheetFilterSave.addEventListener("click", () => {
        saveSheetFilterFromUI();
        applySheetVisibilityToSelect(allowedSheetsCache);
        if (els.sheetFilterDropdown) els.sheetFilterDropdown.classList.add("hidden");
      });
    }

    if (els.themeToggleBtn) {
      els.themeToggleBtn.addEventListener("click", () => {
        const root = document.documentElement;
        const isDark = root.classList.toggle("dark");
        localStorage.setItem("theme", isDark ? "dark" : "light");
      });
    }

    function openMobile() {
      setQuickNavVisible(false); // ✅ sama bank.html
      els.mobileSidebar.classList.remove("-translate-x-full");
      els.sidebarOverlay.classList.remove("hidden");
    }
    function closeMobile() {
      els.mobileSidebar.classList.add("-translate-x-full");
      els.sidebarOverlay.classList.add("hidden");
      setQuickNavVisible(true); // ✅ sama bank.html
    }
    if (els.hamburgerBtn) els.hamburgerBtn.addEventListener("click", (e) => { e.stopPropagation(); openMobile(); });
    if (els.closeSidebarBtn) els.closeSidebarBtn.addEventListener("click", closeMobile);
    if (els.sidebarOverlay) els.sidebarOverlay.addEventListener("click", closeMobile);

    document.addEventListener("click", (e) => {
      if (!els.brandDropdown.classList.contains("hidden")) {
        const wrap = document.getElementById("brandPickerWrap");
        if (wrap && !wrap.contains(e.target)) els.brandDropdown.classList.add("hidden");
      }
      if (!els.userDropdown.classList.contains("hidden")) {
        if (!els.userBtn.contains(e.target) && !els.userDropdown.contains(e.target)) els.userDropdown.classList.add("hidden");
      }
      if (els.sheetFilterDropdown && !els.sheetFilterDropdown.classList.contains("hidden")) {
        const wrap = els.sheetFilterWrap;
        if (wrap && !wrap.contains(e.target)) els.sheetFilterDropdown.classList.add("hidden");
      }
    });

    // ✅ init quick nav
    setupQuickNav();
    setQuickNavVisible(true);
  }

  function greet() {
    const uname = escapeHTML(els.topUser?.textContent || PANEL_USER || "User");
    renderBotBubble(`<div><strong>Halo "${uname}"!</strong> Tempel format WD 8 baris, pilih sheet, lalu klik Kirim.</div>`, Date.now());
  }

  function wireComposer() {
    let composing = false;
    els.chatInput.addEventListener('compositionstart', () => { composing = true; });
    els.chatInput.addEventListener('compositionend', (e) => {
      composing = false;
      autoGrowSmooth(e.target);
      setParseHint(e.target.value);
    });

    els.chatInput.addEventListener("input", () => {
      if (composing) return;
      autoGrowSmooth(els.chatInput);
      setParseHint(els.chatInput.value);
      localStorage.setItem(draftKey(), els.chatInput.value || "");
    });

    els.chatInput.addEventListener("keydown", (e) => {
      if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); els.sendBtn.click(); }
      if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "enter") { e.preventDefault(); els.sendBtn.click(); }
    });

    els.sendBtn.addEventListener("click", doSend);

    els.pasteBtn.addEventListener("click", async () => {
      try {
        const txt = await navigator.clipboard.readText();
        if (txt) {
          els.chatInput.value = txt;
          setParseHint(txt);
          autoGrowSmooth(els.chatInput);
        }
      } catch (e) {}
      els.chatInput.focus();
    });

    els.sheetSelect.addEventListener("change", () => {
      if (els.sheetStatus) els.sheetStatus.textContent = `Sheet aktif: ${els.sheetSelect.value || "-"}`;
      localStorage.setItem(LS_SHEET_KEY(activeBrand), els.sheetSelect.value || "");
    });

    els.refreshSheets.addEventListener("click", loadSheets);

    if (els.clearHistory) {
      els.clearHistory.addEventListener("click", () => {
        clearChatLog();
        localStorage.removeItem(draftKey());
        els.chatList.innerHTML = "";
        greet();
        scrollChatToBottom();
      });
    }
  }

  function setupAlwaysFocusComposer() {
    function isFocusable(el) {
      return !!el.closest('input,textarea,select,button,a,[contenteditable="true"],[role="button"],[data-no-autofocus]');
    }
    document.addEventListener("click", (e) => {
      if (isFocusable(e.target)) return;
      const sel = window.getSelection && String(window.getSelection());
      if (sel && sel.length) return;
      setTimeout(() => els.chatInput?.focus({ preventScroll: true }), 0);
    });
  }

  function applySidebar(isSuperadmin, scopes) {
    const htmlDesktop = renderSidebar(activeBrand, "Desktop", { isSuperadmin, scopes });
    const htmlMobile = renderSidebar(activeBrand, "Mobile", { isSuperadmin, scopes });
    els.sideMenuDesktop.innerHTML = htmlDesktop;
    els.sideMenuMobile.innerHTML = htmlMobile;
    attachSidebarToggle("Desktop");
    attachSidebarToggle("Mobile");
    updateSidebarClock();
    setInterval(updateSidebarClock, 1000);
  }

  function showForbiddenOverlay() {
    if (!els.forbiddenOverlay) return;
    els.forbiddenOverlay.classList.remove("hidden");
    [els.chatInput, els.sendBtn, els.pasteBtn, els.sheetSelect, els.refreshSheets, els.clearHistory].forEach(el => {
      if (el) el.disabled = true;
    });
  }

  (async function init() {
    const session = await requireSession();
    els.topUser.textContent = session?.username || "admin";
    PANEL_USER = session?.username || "admin";
    const isSuperadmin = (session?.role === "superadmin");
    const scopes = normalizeScopes(session?.scopes ?? session?.permissions ?? session?.perms ?? session?.scope_map);

    applyStatic();
    applySidebar(isSuperadmin, scopes);

    if (!hasScope(REQUIRED_SCOPE_PAGE, { isSuperadmin, scopes })) {
      showForbiddenOverlay();
      return;
    }

    const dk = draftKey();
    const draft = localStorage.getItem(dk) || "";
    if (draft) {
      els.chatInput.value = draft;
      setParseHint(draft);
    }
    autoGrowSmooth(els.chatInput);

    const history = loadChatLog();
    if (history.length > 0) {
      for (const item of history) {
        if (item.from === "user") renderUserBubble(item.text || "", item.ts);
        else renderBotBubble(item.html || `<div>${escapeHTML(item.text || "")}</div>`, item.ts);
      }
    } else {
      greet();
    }

    scrollChatToBottom();

    wireComposer();
    await loadSheets();
    setupAlwaysFocusComposer();
    setParseHint("");
    els.chatInput.focus();
  })();

  if (els.logoutBtn) {
    els.logoutBtn.addEventListener("click", async () => {
      await apiFetch("/api/logout", { method: "POST" });
      window.location = "login.html";
    });
  }