/* ============================================================
   shell.jsx — store provider, nav, routing, tweaks, render
   Backed by the API server (app/api.js): data loads from /bootstrap,
   every mutation calls the API then refreshes. The store interface is
   unchanged, so screen components stay the same.
   ============================================================ */

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#b07d4e",
  "cartLayout": "compact",
  "density": "regular"
}/*EDITMODE-END*/;

const ACCENTS = [
  { id: "#b07d4e", name: "คาราเมล" },
  { id: "#6f8a4e", name: "มัทฉะ" },
  { id: "#b0556a", name: "เบอร์รี่" },
];

function deriveAccentInk(hex) { return "#ffffff"; }

/* role → what they can see/do (UI mirror of server/access.js; server enforces) */
const ROLE_ACCESS = {
  admin:      { screens: ["pos", "dashboard", "report", "inventory", "branches", "users", "recipe"], allBranches: true,  addBranch: true,  manageUsers: "all",     editRecipe: true,  manageStock: true,  manageCatalog: true,  restockToPar: true,  home: "dashboard", label: "Admin",      scopeNote: "เห็นและจัดการได้ทุกสาขา" },
  hq_manager: { screens: ["pos", "dashboard", "report", "inventory", "recipe"],                      allBranches: true,  addBranch: false, manageUsers: "none",     editRecipe: false, manageStock: false, manageCatalog: false, restockToPar: false, home: "dashboard", label: "HQ Manager", scopeNote: "ดูได้ทุกสาขา · เทียบเท่า Manager" },
  manager:    { screens: ["pos", "report", "inventory"],                                             allBranches: false, addBranch: false, manageUsers: "none",     editRecipe: false, manageStock: false, manageCatalog: false, restockToPar: false, home: "pos",      label: "Manager",    scopeNote: "เฉพาะสาขาของตน" },
  staff:      { screens: ["pos", "inventory"],                                                       allBranches: false, addBranch: false, manageUsers: "none",    editRecipe: false, manageStock: true,  manageCatalog: false, restockToPar: false, home: "pos",      label: "Staff",      scopeNote: "หน้าขาย POS + จัดการสต็อกสาขาตน" },
};

function App() {
  const [tw, setTweak] = window.useTweaks(TWEAK_DEFAULTS);
  const D = window.POS_DATA, H = window.POS_HELP;

  const [currentUser, setCurrentUser] = useState(null);
  const [access, setAccess] = useState(null);
  const [loading, setLoading] = useState(false);
  const [loginErr, setLoginErr] = useState("");
  const [screen, setScreen] = useState("pos");

  const [branches, setBranches] = useState([]);
  const [currentBranchId, setCurrentBranchId] = useState(null);
  const [inventory, setInventory] = useState({});
  const [recipes, setRecipes] = useState({});
  const [users, setUsers] = useState([]);
  const [ingredients, setIngredients] = useState([]);
  const [products, setProducts] = useState([]);
  const [categories, setCategories] = useState([]);

  const ingOf = (id) => ingredients.find((x) => x.id === id);
  const productOf = (id) => products.find((x) => x.id === id);
  // cost per unit: raw = its cost; mini = (sum of components cost) / batchYield
  const ingCost = (id) => {
    const g = ingOf(id);
    if (!g) return 0;
    if (g.kind === "mini") {
      const batch = (g.components || []).reduce((s, c) => s + (ingOf(c.i)?.cost || 0) * c.q, 0);
      return g.batchYield ? batch / g.batchYield : 0;
    }
    return g.cost || 0;
  };

  /* ---- load everything for the logged-in user ---- */
  async function refresh() {
    const d = await window.API.bootstrap();
    setBranches(d.branches);
    setInventory(d.inventory);
    setRecipes(d.recipes);
    setUsers(d.users);
    setIngredients(d.ingredients);
    setProducts(d.products);
    setCategories(d.categories);
    // members/promotions are read directly from window.POS_DATA by pos.jsx
    window.POS_DATA.members = d.members;
    window.POS_DATA.promotions = d.promotions;
    return d;
  }
  const errToast = (title, e) => window.toast({ tone: "warn", title, msg: (e && e.message) || "เกิดข้อผิดพลาด" });

  /* ---- auth ---- */
  async function login(pin) {
    setLoading(true); setLoginErr("");
    try {
      const r = await window.API.login(pin);     // { token, user, access }
      const d = await refresh();
      setAccess(r.access);
      if (!r.access.allBranches && r.user.branchId) setCurrentBranchId(r.user.branchId);
      else setCurrentBranchId((d.branches[0] || {}).id || null);
      setScreen(r.access.home);
      setCurrentUser(r.user);                     // set last → app renders with data ready
    } catch (e) {
      setLoginErr(e.message || "เข้าสู่ระบบไม่สำเร็จ");
      throw e;
    } finally {
      setLoading(false);
    }
  }
  function logout() {
    window.API.logout();
    setCurrentUser(null); setAccess(null);
    setBranches([]); setInventory({}); setRecipes({}); setUsers([]);
    setIngredients([]); setProducts([]); setCategories([]);
  }

  /* ---- sale ---- */
  async function recordSale(branchId, cart, totals) {
    const lines = cart.map((x) => ({ product_id: x.pid, name: x.name, qty: x.qty,
      unit_price: x.price, shot: !!x.shot, options: { temp: x.temp, sweet: x.sweet, shot: x.shot } }));
    try {
      const r = await window.API.sale({ branchId, lines, payment: totals.method,
        memberId: totals.member ? totals.member.id : null,
        promotionId: totals.promo ? totals.promo.id : null, discount: totals.discount || 0 });
      await refresh();
      return { lowAlerts: r.low_alerts || [] };
    } catch (e) {
      errToast("ขายไม่สำเร็จ", e);
      return { lowAlerts: [], failed: true };
    }
  }

  /* ---- inventory ---- */
  async function receiveStock(branchId, ingId, qty) {
    try { await window.API.receive({ branchId, ingredientId: ingId, qty }); await refresh(); }
    catch (e) { errToast("รับเข้าไม่สำเร็จ", e); }
  }
  async function restockAll(branchId) {
    try { await window.API.restock({ branchId }); await refresh();
      window.toast({ title: "เติมสต็อกแล้ว", msg: "เติมวัตถุดิบที่ใกล้หมดทั้งหมดถึงระดับ par" }); }
    catch (e) { errToast("เติมสต็อกไม่สำเร็จ", e); }
  }
  async function produceMini(branchId, miniId, batches) {
    try {
      const r = await window.API.produce({ branchId, miniId, batches }); await refresh();
      const m = ingOf(miniId);
      window.toast({ title: "ผลิต" + (m ? m.name : "") + "แล้ว", msg: "+" + Number(r.made).toLocaleString() + " " + (m ? m.unit : "") });
    } catch (e) { errToast("ผลิตไม่สำเร็จ", e); }
  }

  /* ---- catalog CRUD ---- */
  async function addIngredient(data) {
    try { await window.API.addIngredient(data); await refresh();
      if (data.kind === "mini") window.toast({ title: "เพิ่มมินิโปรดักแล้ว", msg: data.name + " · มีสต็อกของตัวเอง" });
      else window.toast({ title: "เพิ่มวัตถุดิบแล้ว", msg: data.name + " · ผูกเข้าทุกสาขา" }); }
    catch (e) { errToast("เพิ่มวัตถุดิบไม่สำเร็จ", e); }
  }
  async function updateIngredient(id, data) {
    try { await window.API.updateIngredient(id, data); await refresh(); }
    catch (e) { errToast("บันทึกไม่สำเร็จ", e); }
  }
  async function removeIngredient(id) {
    const g = ingOf(id);
    try { await window.API.removeIngredient(id); await refresh();
      window.toast({ tone: "warn", title: "ลบวัตถุดิบแล้ว", msg: (g ? g.name : id) + " · ถอดออกจากสูตรที่เกี่ยวข้อง" }); }
    catch (e) { errToast("ลบไม่สำเร็จ", e); }
  }
  async function addProduct(data) {
    try { const r = await window.API.addProduct(data); await refresh();
      window.toast({ title: "เพิ่มเมนูแล้ว", msg: data.name + " · " + H.thb(data.price) }); return r.id; }
    catch (e) { errToast("เพิ่มเมนูไม่สำเร็จ", e); return null; }
  }
  async function updateProduct(id, data) {
    try { await window.API.updateProduct(id, data); await refresh(); }
    catch (e) { errToast("บันทึกเมนูไม่สำเร็จ", e); }
  }
  async function removeProduct(id) {
    const p = productOf(id);
    try { await window.API.removeProduct(id); await refresh();
      window.toast({ tone: "warn", title: "ลบเมนูแล้ว", msg: p ? p.name : id }); }
    catch (e) { errToast("ลบเมนูไม่สำเร็จ", e); }
  }
  async function addCategory(name) {
    try { await window.API.addCategory(name); await refresh();
      window.toast({ title: "เพิ่มหมวดหมู่แล้ว", msg: name }); }
    catch (e) { errToast("เพิ่มหมวดหมู่ไม่สำเร็จ", e); }
  }
  async function updateCategory(id, name) {
    try { await window.API.updateCategory(id, name); await refresh(); }
    catch (e) { errToast("บันทึกหมวดหมู่ไม่สำเร็จ", e); }
  }
  async function removeCategory(id) {
    try { await window.API.removeCategory(id); await refresh(); window.toast({ title: "ลบหมวดหมู่แล้ว" }); }
    catch (e) { errToast("ลบหมวดหมู่ไม่ได้", e); }
  }
  async function updateRecipe(pid, ingId, delta) {
    try { await window.API.updateRecipe(pid, ingId, delta); await refresh(); }
    catch (e) { errToast("แก้สูตรไม่สำเร็จ", e); }
  }
  async function removeRecipeItem(pid, ingId) {
    try { await window.API.removeRecipeItem(pid, ingId); await refresh(); }
    catch (e) { errToast("ลบส่วนผสมไม่สำเร็จ", e); }
  }

  /* ---- users ---- */
  async function addUser(data) {
    try { const r = await window.API.addUser(data); await refresh();
      const roleL = { hq_manager: "HQ Manager", manager: "Manager", staff: "Staff" }[data.role] || data.role;
      window.toast({ title: "เพิ่มผู้ใช้สำเร็จ", msg: data.name + " · " + roleL + " · PIN " + r.pin }); }
    catch (e) { errToast("เพิ่มผู้ใช้ไม่สำเร็จ", e); }
  }
  async function updateUser(id, data) {
    try { await window.API.updateUser(id, data); await refresh(); }
    catch (e) { errToast("บันทึกผู้ใช้ไม่สำเร็จ", e); }
  }
  async function removeUser(id) {
    try { await window.API.removeUser(id); await refresh(); }
    catch (e) { errToast("ลบผู้ใช้ไม่สำเร็จ", e); }
  }
  async function toggleUserStatus(id) {
    try { await window.API.toggleUser(id); await refresh(); }
    catch (e) { errToast("เปลี่ยนสถานะไม่สำเร็จ", e); }
  }
  async function resetUserPin(id) {
    try { const r = await window.API.resetPin(id); window.toast({ title: "ตั้ง PIN ใหม่แล้ว", msg: "PIN ใหม่: " + r.pin + " (โชว์ครั้งเดียว)", duration: 8000 }); return r.pin; }
    catch (e) { errToast("รีเซ็ต PIN ไม่สำเร็จ", e); }
  }

  /* ---- branches ---- */
  async function addBranch(data) {
    try { const r = await window.API.addBranch(data); await refresh();
      window.toast({ title: "บัญชีผู้จัดการสาขา", msg: "PIN เข้าระบบ: " + r.managerPin }); }
    catch (e) { errToast("เพิ่มสาขาไม่สำเร็จ", e); }
  }

  /* ---- derived ---- */
  function sessionByBranch() { return {}; } // today's totals already baked into branch.salesToday
  function allLowStock() {
    const out = [];
    Object.keys(inventory).forEach((bid) => {
      (inventory[bid] || []).forEach((it) => { if (it.onHand <= it.reorder) out.push({ bid, id: it.id }); });
    });
    return out;
  }
  function visibleBranches() { return branches; } // bootstrap already scoped to the role

  // enforce: lock non-HQ users to their branch; redirect disallowed screens
  useEffect(() => {
    if (!currentUser || !access) return;
    if (!access.allBranches && currentUser.branchId && currentBranchId !== currentUser.branchId) {
      setCurrentBranchId(currentUser.branchId);
    }
    if (!access.screens.includes(screen)) setScreen(access.home);
  }, [currentUser, screen, currentBranchId]);

  const store = {
    tweaks: tw, screen, go: setScreen,
    branches, currentBranchId, setBranch: setCurrentBranchId,
    inventory, recipes, users,
    ingredients, products, categories, ing: ingOf, product: productOf, ingCost,
    recordSale, receiveStock, restockAll, addBranch, updateRecipe, removeRecipeItem,
    addUser, updateUser, removeUser, toggleUserStatus, resetUserPin,
    addIngredient, updateIngredient, removeIngredient, produceMini,
    addProduct, updateProduct, removeProduct,
    addCategory, updateCategory, removeCategory,
    sessionByBranch, allLowStock,
    currentUser, access, visibleBranches, logout,
  };

  /* ---- not logged in → login screen ---- */
  if (!currentUser || !access) {
    return <window.LoginScreen onSubmit={login} error={loginErr} loading={loading} />;
  }

  const branch = branches.find((b) => b.id === currentBranchId) || branches[0] || {};
  const alertsCount = allLowStock().length;

  const allNav = [
    { group: "ขายหน้าร้าน", items: [{ id: "pos", name: "หน้าขาย POS", icon: "pos" }] },
    { group: "บริหารจัดการ", items: [
      { id: "dashboard", name: "แดชบอร์ดภาพรวม", icon: "grid" },
      { id: "report", name: "รายงานประจำวัน", icon: "report" },
      { id: "inventory", name: "จัดการสต็อก", icon: "box", badge: alertsCount },
      { id: "branches", name: "จัดการสาขา", icon: "store" },
      { id: "users", name: "จัดการผู้ใช้งาน", icon: "user" },
      { id: "recipe", name: "เมนู & สูตร", icon: "list" },
    ] },
  ];
  const nav = allNav.map((g) => ({ ...g, items: g.items.filter((it) => access.screens.includes(it.id)) })).filter((g) => g.items.length);

  const SCREENS = {
    pos: window.PosScreen, dashboard: window.Dashboard, report: window.DailyReport,
    inventory: window.Inventory, branches: window.Branches, recipe: window.Recipe,
    users: window.Users,
  };
  const Current = SCREENS[screen] || window.PosScreen;
  const isPos = screen === "pos";
  const roleLabel = { admin: "Admin", hq_manager: "HQ Manager", manager: "Manager", staff: "Staff" };
  const branchLabel = currentUser && currentUser.branchId ? "สาขา" + (branches.find((b) => b.id === currentUser.branchId) || {}).name : "ทุกสาขา";
  const vBranches = visibleBranches();

  return (
    <window.AppCtx.Provider value={store}>
    <div className="app" style={{ "--accent": tw.accent, "--accent-ink": deriveAccentInk(tw.accent) }}>
      {/* sidebar */}
      <aside className="rail">
        <div className="rail-brand">
          <span className="rail-logo">◐</span>
          <div><div className="rail-name">POS Coffee</div><div className="rail-role">{access.label} Console</div></div>
        </div>

        <div className="rail-branch">
          <div className="rb-l">สาขาที่ใช้งาน</div>
          {access.allBranches ? (
            <select className="rb-select" value={currentBranchId || ""} onChange={(e) => setCurrentBranchId(e.target.value)}>
              {vBranches.map((b) => <option key={b.id} value={b.id}>สาขา{b.name} · {b.code}</option>)}
            </select>
          ) : (
            <div className="rb-locked">สาขา{branch.name} · {branch.code}<span className="rb-lock">ล็อก</span></div>
          )}
        </div>

        <nav className="rail-nav">
          {nav.map((g) => (
            <div className="rail-group" key={g.group}>
              <div className="rg-label">{g.group}</div>
              {g.items.map((it) => (
                <button key={it.id} className={"rail-item" + (screen === it.id ? " on" : "")} onClick={() => setScreen(it.id)}>
                  <Icon name={it.icon} size={18} />
                  <span>{it.name}</span>
                  {it.badge ? <span className="rail-badge">{it.badge}</span> : null}
                </button>
              ))}
            </div>
          ))}
        </nav>

        <div className="rail-foot">
          <div className="rf-user">
            <span className="rf-av">{currentUser.name[0]}</span>
            <div className="rf-meta"><div className="rf-n">{currentUser.name}</div><div className="rf-r">{roleLabel[currentUser.role]} · {branchLabel}</div></div>
            <button className="rf-logout" onClick={logout} title="ออกจากระบบ"><Icon name="arrow" size={16} /></button>
          </div>
        </div>
      </aside>

      {/* content */}
      <main className={"content" + (isPos ? " content-pos" : "")}>
        <Current />
      </main>

      {/* tweaks */}
      <window.TweaksPanel>
        <window.TweakSection label="ธีม & การแสดงผล" />
        <window.TweakColor label="โทนสีหลัก" value={tw.accent} options={ACCENTS.map((a) => a.id)} onChange={(v) => setTweak("accent", v)} />
        <window.TweakRadio label="เลย์เอาต์ตะกร้า" value={tw.cartLayout} options={["compact", "card"]} onChange={(v) => setTweak("cartLayout", v)} />
        <window.TweakRadio label="ความหนาแน่น POS" value={tw.density} options={["regular", "compact"]} onChange={(v) => setTweak("density", v)} />
      </window.TweaksPanel>

      <ToastHost />
    </div>
    </window.AppCtx.Provider>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
