// App shell — WCA junior 牙科領袖營 · 戰情控制台
(() => {
const { Badge, Button, Input } = window.WCATalentGameDesignSystem_377d00;
const { Modal, FormRow, ModalActions, useIsMobile } = window.WCA_UI;
const { userRoleLabel, rank } = window.WCA_UTIL;

const NAV = [
  { id: "dashboard", label: "戰情總覽", glyph: "◆" },
  { id: "roster", label: "名單", glyph: "⚑" },
  { id: "flow", label: "活動流程", glyph: "☷" },
  { id: "merch", label: "文宣清單", glyph: "✦" },
  { id: "contacts", label: "聯絡窗口", glyph: "☎" },
];
const ADMIN_NAV = { id: "admin", label: "帳號管理", glyph: "⛨" };
const TITLES = {
  dashboard: ["戰情總覽", "Talent Game · Hackathon · Lecture 作戰儀表板"],
  roster: ["名單管理", "工作人員 · 導師 · 講師 · 學員 · 來賓 · 廠商 · 房間分配"],
  flow: ["活動流程", "簡易流程 · 詳細流程 · 器材道具"],
  merch: ["文宣清單", "輸出品製作與攜帶查核"],
  contacts: ["聯絡窗口", "場地 · 接駁 · 住宿 · 醫護"],
  admin: ["帳號管理", "Admin · Leader · Member 權限"],
};

function PasswordModal({ onClose }) {
  const [cur, setCur] = React.useState("");
  const [nxt, setNxt] = React.useState("");
  const save = async () => {
    await api("PUT", "/api/me/password", { current: cur, next: nxt });
    alert("密碼已更新");
    onClose();
  };
  return (
    <Modal title="修改密碼" onClose={onClose} width={400}>
      <FormRow cols="1fr"><Input label="目前密碼" type="password" value={cur} onChange={(e) => setCur(e.target.value)} /></FormRow>
      <FormRow cols="1fr"><Input label="新密碼（至少 6 碼）" type="password" value={nxt} onChange={(e) => setNxt(e.target.value)} /></FormRow>
      <ModalActions onSave={save} onCancel={onClose} />
    </Modal>
  );
}

function Sidebar({ view, setView, me, drawer = false }) {
  const [pwOpen, setPwOpen] = React.useState(false);
  const nav = me.role === "admin" ? [...NAV, ADMIN_NAV] : NAV;
  const base = { width: 232, flexShrink: 0, background: "var(--navy-900)", borderRight: "1px solid var(--border-default)", display: "flex", flexDirection: "column", padding: "22px 16px", height: "100vh", overflowY: "auto", boxSizing: "border-box" };
  const pos = drawer
    ? { position: "fixed", top: 0, left: 0, bottom: 0, zIndex: 210, boxShadow: "var(--shadow-xl)" }
    : { position: "sticky", top: 0, alignSelf: "flex-start", minHeight: "100vh" };
  return (
    <aside style={{ ...base, ...pos }}>
      <div style={{ textAlign: "center", paddingBottom: 16, borderBottom: "1px solid var(--divider)", marginBottom: 16 }}>
        <img src="/assets/brand/wca-logo.png" alt="WCA · White Coat Accelerator" style={{ width: 176, height: "auto", display: "block", margin: "0 auto", borderRadius: "var(--radius-md)", boxShadow: "0 0 22px rgba(212,175,55,.18)" }} />
        <div style={{ fontSize: 16.5, color: "var(--text-muted)", marginTop: 10, letterSpacing: ".14em" }}>2026 牙 科 領 袖 營</div>
      </div>
      <nav style={{ display: "flex", flexDirection: "column", gap: 4 }}>
        {nav.map((n) => {
          const active = n.id === view;
          return (
            <button key={n.id} onClick={() => setView(n.id)} style={{
              display: "flex", alignItems: "center", gap: 12, padding: "11px 14px", cursor: "pointer",
              fontFamily: "var(--font-serif)", fontSize: 15, letterSpacing: ".06em", textAlign: "left",
              color: active ? "var(--navy-950)" : "var(--text-secondary)",
              background: active ? "var(--grad-gold)" : "transparent",
              border: active ? "1px solid var(--gold-300)" : "1px solid transparent",
              borderRadius: "var(--radius-sm)", boxShadow: active ? "var(--glow-gold-sm)" : "none",
              fontWeight: active ? 700 : 500, transition: "all var(--dur-med)",
            }}>
              <span style={{ width: 18, textAlign: "center", opacity: active ? 1 : .7 }}>{n.glyph}</span>
              {n.label}
            </button>
          );
        })}
      </nav>
      <div style={{ marginTop: "auto", paddingTop: 16, borderTop: "1px solid var(--divider)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 12 }}>
          {me.avatar && window.WCA_AVATARS[me.avatar] ? (
            <img src={window.WCA_AVATARS[me.avatar].src} alt="" style={{ width: 38, height: 38, borderRadius: "50%", objectFit: "cover", objectPosition: "top center", imageRendering: "pixelated", border: "2px solid var(--gold-500)", boxShadow: "var(--glow-gold-sm)", flexShrink: 0 }} />
          ) : (
            <span style={{ width: 38, height: 38, borderRadius: "50%", background: "var(--grad-gold)", color: "var(--navy-950)", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-serif)", fontWeight: 900, fontSize: 16, border: "2px solid var(--gold-500)" }}>
              {(me.display_name || me.username)[0]}
            </span>
          )}
          <div style={{ lineHeight: 1.3, minWidth: 0 }}>
            <div style={{ fontSize: 13, color: "var(--text-primary)", fontFamily: "var(--font-serif)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{me.display_name || me.username}</div>
            <div style={{ fontSize: 10.5, color: "var(--text-muted)" }}>{userRoleLabel[me.role]}</div>
          </div>
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <Button variant="ghost" size="sm" style={{ flex: 1 }} onClick={() => setPwOpen(true)}>密碼</Button>
          <Button variant="ghost" size="sm" style={{ flex: 1 }} onClick={async () => { await api("POST", "/api/logout"); location.href = "/login.html"; }}>登出</Button>
        </div>
      </div>
      {pwOpen && <PasswordModal onClose={() => setPwOpen(false)} />}
    </aside>
  );
}

function countdown(meta) {
  if (!meta.event_start) return "";
  const start = new Date(meta.event_start + "T00:00:00+08:00");
  const days = Math.ceil((start - Date.now()) / 86400000);
  if (days > 0) return "倒數 T-" + days;
  if (days > -3) return "作戰進行中";
  return "已結營";
}

function Topbar({ view, meta, mobile, onMenu }) {
  const [t, sub] = TITLES[view];
  return (
    <header style={{ display: "flex", alignItems: "center", gap: mobile ? 12 : 16, padding: mobile ? "14px 14px" : "18px 28px", borderBottom: "1px solid var(--border-default)", background: "linear-gradient(180deg,var(--navy-850),transparent)" }}>
      {mobile && (
        <button onClick={onMenu} aria-label="選單" style={{
          width: 42, height: 42, flexShrink: 0, cursor: "pointer", fontSize: 20, lineHeight: 1,
          color: "var(--gold-300)", background: "var(--navy-850)",
          border: "1px solid var(--border-strong)", borderRadius: "var(--radius-sm)",
          display: "flex", alignItems: "center", justifyContent: "center",
        }}>☰</button>
      )}
      <div style={{ minWidth: 0 }}>
        <h1 style={{ margin: 0, fontFamily: "var(--font-serif)", fontWeight: 900, fontSize: mobile ? 20 : 26, letterSpacing: ".08em", background: "var(--grad-gold-text)", WebkitBackgroundClip: "text", backgroundClip: "text", color: "transparent", whiteSpace: "nowrap" }}>{t}</h1>
        {!mobile && <div style={{ fontSize: 12.5, color: "var(--text-muted)", marginTop: 2 }}>{sub}</div>}
      </div>
      <div style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: mobile ? 10 : 20 }}>
        {!mobile && (
          <div style={{ textAlign: "right" }}>
            <div style={{ fontSize: 13, color: "var(--text-gold)", fontFamily: "var(--font-serif)" }}>{meta.event_date}</div>
            <div style={{ fontSize: 11.5, color: "var(--text-muted)" }}>{meta.event_venue}</div>
          </div>
        )}
        <Badge tone="ember" dot>{countdown(meta)}</Badge>
      </div>
    </header>
  );
}

function App() {
  const [me, setMe] = React.useState(null);
  const [data, setData] = React.useState(null);
  const initial = location.hash.slice(1);
  const [view, setViewRaw] = React.useState(TITLES[initial] ? initial : "dashboard");
  const setView = (v) => { location.hash = v; setViewRaw(v); };
  const isMobile = useIsMobile();
  const [menuOpen, setMenuOpen] = React.useState(false);

  const refresh = React.useCallback(async () => {
    setData(await api("GET", "/api/data"));
  }, []);

  React.useEffect(() => {
    (async () => {
      try {
        const res = await fetch("/api/me");
        if (res.status === 401) { location.href = "/login.html"; return; }
        setMe(await res.json());
        await refresh();
      } catch (e) { console.error(e); }
    })();
  }, [refresh]);

  if (!me || !data) {
    return (
      <div style={{ minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center", background: "var(--grad-night)" }}>
        <div style={{ fontFamily: "var(--font-serif)", color: "var(--text-gold)", fontSize: 18, letterSpacing: ".2em" }}>召 喚 中 …</div>
      </div>
    );
  }

  const canEdit = rank[me.role] >= rank.leader;
  const Views = { dashboard: window.Dashboard, roster: window.Roster, flow: window.FlowSchedule, merch: window.MerchChecklist, contacts: window.Contacts, admin: window.AdminUsers };
  const Current = Views[view] || window.Dashboard;
  const changeView = (v) => { setView(v); setMenuOpen(false); };
  return (
    <div style={{ display: "flex", minHeight: "100vh", background: "var(--grad-night)" }}>
      {/* 主視窗底圖：魔幻古戰場地圖＋深色遮罩（fixed 層避免 iOS background-attachment 問題） */}
      <div aria-hidden style={{
        position: "fixed", inset: 0, zIndex: 0, pointerEvents: "none",
        background: "linear-gradient(rgba(5,7,15,.5), rgba(5,7,15,.68)), url(/assets/brand/battlefield-map.jpg) center / cover no-repeat",
      }} />
      {!isMobile && <Sidebar view={view} setView={changeView} me={me} />}
      {isMobile && menuOpen && (
        <React.Fragment>
          <div onClick={() => setMenuOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 200, background: "rgba(5,7,15,.66)" }} />
          <Sidebar view={view} setView={changeView} me={me} drawer />
        </React.Fragment>
      )}
      <div style={{ flex: 1, minWidth: 0, display: "flex", flexDirection: "column", position: "relative", zIndex: 1 }}>
        <Topbar view={view} meta={data.meta} mobile={isMobile} onMenu={() => setMenuOpen(true)} />
        <main style={{ flex: 1, padding: isMobile ? "16px 12px 40px" : "26px 28px 40px", overflow: "auto" }}>
          <Current data={data} refresh={refresh} me={me} canEdit={canEdit} />
        </main>
      </div>
    </div>
  );
}
window.App = App;
})();
