/* ==========================================================================
 * ADMIN NEXT — app.jsx  (แยกจาก index.html เดิม; โหลดผ่าน <script type="text/babel">)
 * โหลดตามลำดับใน index.html — ทุกไฟล์แชร์ scope เดียวกัน (babel-standalone)
 * ========================================================================== */

/* สิทธิ์ที่จำเป็นต่อการเข้าแต่ละหน้า (banks เข้าได้ถ้ามีสิทธิ์บัญชีอย่างใดอย่างหนึ่ง) */
const NX_PAGE_PERM = { home:["home"], overview:["summary"], members:["users"], deposits:["deposits"], withdrawals:["wdr"], bankreceive:["bank-receive","accounts"], bankpayout:["bank-payout","accounts"], bankcentral:["bank-central","accounts"], logs:["logs"], fraud:["tool_fraud_list","users"], manualreport:["tool_manual_report","users","tool_manage_credit"], suspicious:["tool_suspicious_deposit","accounts","deposits"], topdep:["tool_top_depositors","users","summary"], wheelhist:["tool_history_wheel"], referralhist:["tool_history_referral"], cashbackhist:["tool_history_cashback"], otplog:["tool_otp_log","tool_sms_gateway"], smshist:["tool_sms_history","tool_otp_log","accounts"], allhist:["tool_history_all"], bonushist:["tool_history_bonus"], predhist:["tool_history_prediction"], promoreq:["tool_promo_requests"], profitloss:["tool_report_pl","summary"], promosummary:["tool_report_promo","summary"], affiliate:["tool_affiliate"], affiliatehist:["tool_affiliate"], codes:["codes"], checkin:["tool_checkin"], gamemanager:["game-manager","games"], gamesort:["game-sort","tool_game_order","games"], sitesettings:["settings"], admins:["perm_edit_permissions","perm_change_admin_password"], promo:["promo"], prediction:["prediction"], mktreport:["tool_mkt_report"], mktorgs:["tool_mkt_orgs"], mktlinks:["tool_mkt_links"], domains:["tool_domains","settings","tool_domains_manage","tool_mkt_orgs"], notifications:["tool_notifications","settings"], popupcontact:["tool_popup_contact","settings"], providerlogos:["provider-logos","games"], featuredproviders:["tool_featured_providers","games"], featuredgames:["tool_featured_games","games"], memberlevels:["tool_member_levels","users"], wheel:["tool_wheel"], cashback:["tool_cashback"], whitelabel:["tool_white_label"], serverhealth:["tool_server_health"], apigame:NX_API_GAME_PERMS, apideposit:NX_API_DEPOSIT_PERMS, apidepositspecial:NX_API_DEPOSIT_SPECIAL_PERMS, apisms:["tool_sms_gateway"], leaderboard:["tool_ranking","summary","tool_report_pl","settings_agent"], providerreports:["tool_provider_reports","summary","tool_report_pl","tool_report_promo"], staffkpi:["tool_staff_kpi"], creditmanage:["tool_manage_credit","users"], slipapprove:["tool_slip_approve","deposits","tool_payment_manager"], autopeer:["tool_autopeer","payment"], payment:["payment"], depositchannels:["tool_payment_manager","accounts","bank-receive","users"], cryptodeposit:["tool_payment_manager","payment"], abdconsole:["tool_abd_console","abd-console","accounts"], lineconnect:["tool_line_abd","line-abd","accounts"] };
const NX_PAGE_ORDER = ["home","overview","profitloss","promosummary","leaderboard","providerreports","staffkpi","mktreport","members","memberlevels","topdep","creditmanage","deposits","withdrawals","slipapprove","autopeer","bankreceive","bankpayout","bankcentral","depositchannels","cryptodeposit","payment","suspicious","promoreq","promo","prediction","wheel","cashback","codes","checkin","gamemanager","gamesort","providerlogos","featuredproviders","featuredgames","mktorgs","mktlinks","manualreport","allhist","wheelhist","referralhist","cashbackhist","bonushist","predhist","affiliate","affiliatehist","smshist","otplog","fraud","logs","domains","notifications","popupcontact","sitesettings","whitelabel","serverhealth","apigame","apideposit","apidepositspecial","apisms","abdconsole","lineconnect","admins"];
function nxPageAllowed(pg){ const need=NX_PAGE_PERM[pg]; return !need || canAny(need); }
function nxFirstAllowedPage(){ return NX_PAGE_ORDER.find(nxPageAllowed) || "home"; }

function App() {
  const [theme, setThemeState] = useState(()=>{try{return localStorage.getItem("nxadmin-theme")||"system";}catch{return "system";}});
  const [page, setPage] = useState(()=>{ try{ const h=(location.hash||"").replace(/^#\/?/,""); return NX_PAGES.has(h)?h:"home"; }catch{return "home";} });
  const [sidebar, setSidebar] = useState(false);
  const [toasts, setToasts] = useState([]);
  const [boot, setBoot] = useState("loading"); // loading | ok | auth
  const [admin, setAdmin] = useState(null);
  const [authReason, setAuthReason] = useState("");

  const applyTheme = (t)=>{const r=document.documentElement; r.classList.remove("light","dark"); if(t==="light")r.classList.add("light"); else if(t==="dark")r.classList.add("dark");};
  useEffect(()=>{applyTheme(theme);},[theme]);
  useEffect(()=>{ if(theme!=="system")return; const mq=window.matchMedia("(prefers-color-scheme: dark)"); const h=()=>applyTheme("system"); mq.addEventListener?.("change",h); return ()=>mq.removeEventListener?.("change",h);},[theme]);
  const setTheme=(t)=>{setThemeState(t); try{localStorage.setItem("nxadmin-theme",t);}catch{}};

  const toast=(msg)=>{const id=Date.now()+Math.random(); const isErr=nxIsErrorMessage(msg); const text=isErr?nxErrorText(msg):msg; setToasts(t=>[...t,{id,msg:text,tone:isErr?"error":"success"}]); setTimeout(()=>setToasts(t=>t.filter(x=>x.id!==id)),isErr?7000:2600);};

  // ตรวจสิทธิ์ด้วย token เดิม
  useEffect(()=>{
    window.__nxAuthFail = ()=>{ setAuthReason("เซสชันหมดอายุ กรุณาเข้าสู่ระบบใหม่"); setBoot("auth"); };
    (async()=>{
      if(!getToken()){ setAuthReason(""); setBoot("auth"); return; }
      let idU=null; try{ idU=JSON.parse(localStorage.getItem("adminUser")||"null"); }catch{}
      try {
        const me = await api("/permissions/me");
        // สิทธิ์จริงของแอดมินคือ me.permissions (ไม่ใช่ me.pages ซึ่งเป็นรายการหน้าทั้งหมด)
        NX_PERMS = { set: new Set((me&&me.permissions)||[]), isSuper: !!(me&&me.isSuper), isOwner: !!(me&&me.isOwner) };
        setAdmin({ ...(idU||{}), isSuper:NX_PERMS.isSuper, isOwner:NX_PERMS.isOwner, role:(idU&&idU.role)||null });
        // ลงหน้าแรกที่มีสิทธิ์ ถ้าหน้าปัจจุบัน (จาก hash) ไม่มีสิทธิ์
        let cur="home"; try{ const h=(location.hash||"").replace(/^#\/?/,""); if(NX_PAGES.has(h)) cur=h; }catch{}
        setPage(nxPageAllowed(cur)?cur:nxFirstAllowedPage());
        setBoot("ok");
      }
      catch(e){ if(e.status===401||e.status===403){ setAuthReason("เซสชันหมดอายุ กรุณาเข้าสู่ระบบใหม่"); setBoot("auth"); } else { setAdmin(idU||{}); setBoot("ok"); } }
    })();
  },[]);

  // Keep an authenticated admin session alive only while this console tab is visible.
  // Server-side duration remains approximate; hidden/closed tabs stop sending heartbeats.
  useEffect(()=>{
    if(boot!=="ok" || !getToken()) return;
    let stopped=false;
    const heartbeat=()=>{
      if(stopped || document.visibilityState==="hidden") return;
      api("/admin-session/heartbeat",{method:"POST"}).catch(()=>{});
    };
    heartbeat();
    const timer=window.setInterval(heartbeat,60000);
    const onVisibility=()=>{if(document.visibilityState==="visible")heartbeat();};
    document.addEventListener("visibilitychange",onVisibility);
    window.addEventListener("pageshow",heartbeat);
    return ()=>{
      stopped=true;
      window.clearInterval(timer);
      document.removeEventListener("visibilitychange",onVisibility);
      window.removeEventListener("pageshow",heartbeat);
    };
  },[boot]);

  const acceptLogin = (session) => {
    const user = session?.user;
    if (!session?.token || !user) throw new Error("invalid_login_response");
    try {
      localStorage.setItem("adminToken", session.token);
      localStorage.setItem("adminUser", JSON.stringify(user));
    } catch {
      throw new Error("storage_unavailable");
    }
    NX_PERMS = {
      set: new Set(user.permissions || []),
      isSuper: !!user.isAdminDev,
      isOwner: !!user.isOwner,
    };
    setAdmin(user);
    const current = String(location.hash || "").replace(/^#\/?/, "");
    const target = NX_PAGES.has(current) && nxPageAllowed(current) ? current : nxFirstAllowedPage();
    setPage(target);
    if (location.hash !== "#/" + target) location.hash = "#/" + target;
    setAuthReason("");
    setBoot("ok");
  };

  const logout = () => {
    // Send the real logout event before removing the bearer token.
    if(getToken()) api("/admin-session/logout",{method:"POST"}).catch(()=>{});
    try {
      localStorage.removeItem("adminToken");
      localStorage.removeItem("adminUser");
      localStorage.removeItem("ADMIN_KEY");
    } catch {
      toast("ออกจากระบบไม่สำเร็จ กรุณาลองอีกครั้ง");
      return;
    }
    NX_PERMS = { set: new Set(), isSuper: false, isOwner: false };
    setAdmin(null);
    setAuthReason("");
    setBoot("auth");
  };

  const PAGE_META={ home:["หน้าหลัก","รายการล่าสุด ยอดรอเติม และยอดคงเหลือช่องทางฝาก"], overview:["แดชบอร์ด","สมาชิก ฝากถอน เกม และกิจกรรมในมุมมองเดียว"], members:["สมาชิกทั้งหมด","ค้นหาและจัดการสมาชิก"], deposits:["รายการฝาก","ประวัติและอนุมัติรายการฝาก"], withdrawals:["รายการถอน","ประวัติและอนุมัติรายการถอน"], bankreceive:["บัญชีรับเงิน","จัดการบัญชีรับเงินฝาก"], bankpayout:["บัญชีถอน","จัดการบัญชีถอนเงิน"], bankcentral:["บัญชีกลาง","จัดการบัญชีกลาง"], fraud:["รายชื่อมิจฉาชีพ","บัญชีดำ เบอร์/บัญชี/ชื่อ ที่ต้องระวัง"], logs:["Activity Log","ประวัติการทำงานของผู้ดูแลระบบ"], manualreport:["รายงานเครดิต","ประวัติเติม/ตัด/โบนัส/จำลองเทิร์น"], suspicious:["ฝากน่าสงสัย","สลิป/SMS/LINE ที่ระบบยังจับคู่ไม่ได้"], topdep:["20 อันดับฝากสูงสุด","สมาชิกที่ฝากมากที่สุดตามช่วงเวลา"], wheelhist:["ประวัติวงล้อ","การหมุนและรางวัลที่แจก"], referralhist:["ประวัติชวนเพื่อน","คอมมิชชั่นแนะนำเพื่อน"], cashbackhist:["ประวัติคืนยอดเสีย","การเคลมคืนยอดเสีย"], otplog:["OTP Log","OTP สมัครสมาชิก/ลืมรหัสผ่าน — ผ่าน SMS-KUB (API)"], smshist:["ประวัติ SMS","SMS ธนาคารเข้าระบบฝากอัตโนมัติ — SMS Gateway (ระบบโปรเจค)"], allhist:["ประวัติทั้งหมด","ฝากและถอนรวมในที่เดียว"], bonushist:["ประวัติโบนัส","โบนัสจากทุกช่องทาง"], predhist:["ประวัติทายผล","การทายผลของสมาชิกและผลลัพธ์"], promoreq:["โปรฟรีรออนุมัติ","คำขอรับโปรฟรีที่รอแอดมินอนุมัติ"], profitloss:["กำไร/ขาดทุน","ฝาก ถอน รายจ่าย และกำไรสุทธิรายวัน"], promosummary:["โปรโมชั่น/โบนัส","สรุปการแจกโปร โบนัส คืนยอดเสีย และคอม"], affiliate:["ตั้งค่าพันธมิตร","อัตราค่าคอม 4 ชั้น และการตั้งค่าระบบพันธมิตร"], affiliatehist:["ประวัติพันธมิตร","ประวัติคอมมิชชั่นชวนเพื่อน"], codes:["คูปอง","สร้างและจัดการคูปองเติมเครดิต"], checkin:["เช็คอิน","ตั้งค่ารางวัลเช็คอินรายวัน"], gamemanager:["จัดการค่ายเกม","เปิด/ปิดค่ายและเกม อัพโหลดปก/โลโก้"], gamesort:["เรียงลำดับเกมหน้าเว็บ","ลากสลับลำดับค่ายและเกมที่ลูกค้าเห็น"], sitesettings:["ตั้งค่าเว็บไซต์","ชื่อไซต์ ธีม สี SEO ระบบเงิน"], admins:["ผู้ดูแลระบบ","จัดการทีมงาน สิทธิ์ และรหัสผ่าน"], promo:["โปรโมชั่น","สร้างและจัดการโปรโมชั่นฝากรับโบนัส"], prediction:["ทายผล","สร้างและจัดการกิจกรรมทายผล"], mktreport:["รายงานสายการตลาด","สรุปยอดสมาชิก ฝาก ถอน แยกตามช่องทาง"], mktorgs:["จัดการสายการตลาด","เพิ่ม แก้ไข ลบทีมการตลาด"], mktlinks:["ช่องทางสมัคร","จัดการช่องทางสมัครสมาชิก"], domains:["ตั้งค่าลิงก์ & เชื่อมโดเมน","จัดการโดเมนและ Cloudflare DNS"], notifications:["การแจ้งเตือน","LINE Notify / Telegram / Webhook"], popupcontact:["Popup / ช่องทางติดต่อ","ป๊อปอัพโปรโมชั่นและช่องทางติดต่อ"], providerlogos:["รูปเมนูค่ายเกม","อัพโหลดโลโก้เมนูค่ายเกม"], featuredproviders:["ค่ายเกมยอดนิยม","ปักหมุดค่ายเกมยอดนิยมหน้าเว็บ"], featuredgames:["เกมยอดนิยม","ปักหมุดเกมยอดนิยมหน้าเว็บ"], memberlevels:["ระดับสมาชิก","ตั้งค่าระดับและสิทธิพิเศษสมาชิก"], wheel:["กงล้อ","ตั้งค่ากงล้อนำโชค"], cashback:["คืนยอดเสีย","ตั้งค่าระบบคืนยอดเสีย"], whitelabel:["White Label","ตั้งค่าแบรนด์และ White Label"], serverhealth:["สุขภาพเซิร์ฟเวอร์","ตรวจสอบสถานะเซิร์ฟเวอร์"], apigame:["API Game","ตั้งค่าเชื่อมต่อ API ค่ายเกม"], apideposit:["API ฝาก","ตั้งค่าเชื่อมต่อ API ช่องทางฝาก"], apidepositspecial:["API ฝาก พิเศษ","ตั้งค่าเชื่อมต่อ Slip2Go / Autopeer / AskMePay"], apisms:["API SMS-KUB","ตั้งค่าเชื่อมต่อ SMS Gateway"], leaderboard:["Leaderboard","อันดับผู้เล่นและ Big Win"], providerreports:["รายงานค่ายเกม","ยอดเครดิตและสถิติค่ายเกม"], staffkpi:["KPI พนักงาน","วัดผลงานจากกิจกรรมของทีมงานที่ระบบบันทึกไว้"], creditmanage:["จัดการเครดิต","เติม/ตัดเครดิตและประวัติ"], slipapprove:["อนุมัติสลิป","รายการฝากรออนุมัติ"], autopeer:["รายงาน Autopeer","รายการฝากผ่าน Autopeer (แยกจากรายการฝากปกติ)"], payment:["Payment","ผู้ให้บริการชำระเงินและธุรกรรม"], depositchannels:["จัดการช่องทางฝาก","บัญชีรับฝากเงิน"], cryptodeposit:["ฝาก USDT (คริปโต)","กระเป๋ารับเงิน เรท และยอด USDT ที่เข้ามา"], abdconsole:["ABD Console","จัดการอุปกรณ์ ABD"], lineconnect:["LINE Connect","เชื่อมต่อและจัดการ LINE ABD"] };
  const onNav=(pg,label)=>{ if(pg){ setPage(pg); try{ if(location.hash!=="#/"+pg) location.hash="#/"+pg; }catch{} setSidebar(false);} else { toast("“"+label+"” กำลังพัฒนา"); setSidebar(false);} };
  useEffect(()=>{ const h=()=>{ try{ const k=(location.hash||"").replace(/^#\/?/,""); if(!NX_PAGES.has(k)) return; if(nxPageAllowed(k)){ setPage(k); } else { const fb=nxFirstAllowedPage(); setPage(fb); if(location.hash!=="#/"+fb) location.hash="#/"+fb; } }catch{} }; window.addEventListener("hashchange",h); return ()=>window.removeEventListener("hashchange",h); },[]);
  useEffect(()=>{ try{ if(!location.hash && page) location.hash="#/"+page; }catch{} },[page]);
  const meta=PAGE_META[page]||[page,""];

  if(boot==="loading") return (<div className="flex h-full items-center justify-center"><div className="flex items-center gap-2 text-sm text-muted"><Ic d={I.refresh} size={18} cls="animate-spin"/> กำลังโหลด…</div></div>);
  if(boot==="auth") return <AuthGate reason={authReason} onAuthenticated={acceptLogin}/>;

  return (<div className="flex h-full text-fg">
    <Sidebar open={sidebar} onClose={()=>setSidebar(false)} page={page} onNav={onNav} admin={admin} onLogout={logout}/>
    <div className="flex min-w-0 flex-1 flex-col">
      <Topbar onMenu={()=>setSidebar(true)} theme={theme} setTheme={setTheme} crumb={meta[0]} admin={admin} onNav={onNav}/>
      <CreditStrip/>
      <main className="min-w-0 flex-1 overflow-y-auto">
        <div className="w-full px-4 py-6 sm:px-6 xl:px-8" style={{paddingBottom:"max(1.5rem,env(safe-area-inset-bottom,0px))"}}>
          <div className="mb-5 flex flex-wrap items-end justify-between gap-3">
            <div><h1 className="text-2xl font-bold tracking-tight">{meta[0]}</h1><p className="mt-1 text-sm text-fg-2">{meta[1]}</p></div>
          </div>
          {!nxPageAllowed(page) ? (
            <div className="rounded-xl border border-dashed border-line bg-surface px-4 py-16 text-center shadow-sm">
              <div className="mx-auto mb-2 grid h-10 w-10 place-items-center rounded-full text-warn" style={{background:"var(--warn-soft)"}}><Ic d={I.ban} size={20}/></div>
              <div className="text-sm font-medium text-fg-2">ไม่มีสิทธิ์เข้าถึงหน้านี้</div>
              <p className="mt-1 text-xs text-muted">กรุณาติดต่อผู้ดูแลระบบเพื่อขอสิทธิ์</p>
            </div>
          ) : (<>
            {page==="members" && <MembersPage toast={toast}/>}
            {page==="overview" && <Dashboard toast={toast}/>}
            {page==="home" && <HomePage toast={toast}/>}
            {page==="deposits" && <FinancePage kind="deposit" toast={toast}/>}
            {page==="withdrawals" && <FinancePage kind="withdraw" toast={toast}/>}
            {page==="bankreceive" && <BankReceivePage toast={toast}/>}
            {page==="bankpayout" && <BankPayoutPage toast={toast}/>}
            {page==="bankcentral" && <BankCentralPage toast={toast}/>}
            {page==="fraud" && <FraudListPage toast={toast}/>}
            {page==="logs" && <ActivityLogPage toast={toast}/>}
            {page==="manualreport" && <ManualReportPage toast={toast}/>}
            {page==="suspicious" && <SuspiciousPage toast={toast}/>}
            {page==="topdep" && <TopDepositorsPage toast={toast}/>}
            {page==="wheelhist" && <WheelHistoryPage toast={toast}/>}
            {page==="referralhist" && <ReferralHistoryPage toast={toast}/>}
            {page==="cashbackhist" && <CashbackHistoryPage toast={toast}/>}
            {page==="otplog" && <OtpLogPage toast={toast}/>}
            {page==="smshist" && <SmsHistoryPage toast={toast}/>}
            {page==="allhist" && <AllHistoryPage toast={toast}/>}
            {page==="bonushist" && <BonusHistoryPage toast={toast}/>}
            {page==="predhist" && <PredictionHistoryPage toast={toast}/>}
            {page==="promoreq" && <PromoRequestsPage toast={toast}/>}
            {page==="profitloss" && <ProfitLossPage toast={toast}/>}
            {page==="promosummary" && <PromoSummaryPage toast={toast}/>}
            {page==="affiliate" && <AffiliatePage toast={toast}/>}
            {page==="affiliatehist" && <AffiliateHistoryPage toast={toast}/>}
            {page==="codes" && <CodesPage toast={toast}/>}
            {page==="checkin" && <CheckinPage toast={toast}/>}
            {page==="gamemanager" && <GameManagerPage toast={toast}/>}
            {page==="gamesort" && <GameSortPage toast={toast}/>}
            {page==="sitesettings" && <SettingsPage toast={toast}/>}
            {page==="admins" && <AdminsPage toast={toast}/>}
            {page==="promo" && <PromoPage toast={toast}/>}
            {page==="prediction" && <PredictionPage toast={toast}/>}
            {page==="mktreport" && <MktReportPage toast={toast}/>}
            {page==="mktorgs" && <MktOrgsPage toast={toast}/>}
            {page==="mktlinks" && <MktLinksPage toast={toast}/>}
            {page==="domains" && <DomainsPage toast={toast}/>}
            {page==="notifications" && <NotificationsPage toast={toast}/>}
            {page==="popupcontact" && <PopupContactPage toast={toast}/>}
            {page==="providerlogos" && <ProviderLogosPage toast={toast}/>}
            {page==="featuredproviders" && <FeaturedPage toast={toast}/>}
            {page==="featuredgames" && <FeaturedPage toast={toast}/>}
            {page==="memberlevels" && <MemberLevelsPage toast={toast}/>}
            {page==="wheel" && <WheelPage toast={toast}/>}
            {page==="cashback" && <CashbackPage toast={toast}/>}
            {page==="whitelabel" && <WhiteLabelPage toast={toast}/>}
            {page==="serverhealth" && <ServerHealthPage toast={toast}/>}
            {page==="apigame" && <ApiSettingsPage toast={toast} defaultTab="game"/>}
            {page==="apideposit" && <ApiSettingsPage toast={toast} defaultTab="deposit"/>}
            {page==="apidepositspecial" && <ApiSettingsPage toast={toast} defaultTab="depositSpecial"/>}
            {page==="apisms" && <ApiSettingsPage toast={toast} defaultTab="sms"/>}
            {page==="leaderboard" && <LeaderboardPage toast={toast}/>}
            {page==="providerreports" && <ProviderReportsPage toast={toast}/>}
            {page==="staffkpi" && <StaffKpiPage toast={toast}/>}
            {page==="creditmanage" && <CreditManagePage toast={toast}/>}
            {page==="slipapprove" && <SlipApprovePage toast={toast}/>}
            {page==="autopeer" && <AutopeerPage toast={toast}/>}
            {page==="payment" && <PaymentPage toast={toast}/>}
            {page==="depositchannels" && <DepositChannelsPage toast={toast}/>}
            {page==="cryptodeposit" && <CryptoDepositPage toast={toast}/>}
            {page==="abdconsole" && <AbdConsolePage toast={toast}/>}
            {page==="lineconnect" && <LineConnectPage toast={toast}/>}
          </>)}
        </div>
      </main>
    </div>
    <Toasts items={toasts}/>
  </div>);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App/>);
