/* ===== store.jsx — global state ===== */
(function () {
  const StoreCtx = React.createContext(null);

  function useStore() {
    return React.useContext(StoreCtx);
  }

  function StoreProvider({ children }) {
    const [state, setState] = React.useState(() => ({
      ...window.SEED,
      dismissedAlarms: new Set(),
      // UI
      device: 'desktop',          // 'desktop' | 'mobile' | 'split'
      sidebarCollapsed: false,
      cmdkOpen: false,
      // toasts
      toasts: [],
      // current user
      currentUserId: 'u-2',
    }));

    const set = (patch) => setState((s) => ({ ...s, ...(typeof patch === 'function' ? patch(s) : patch) }));

    // toast helper
    const toast = (text, kind = 'success') => {
      const id = 't-' + Math.random().toString(36).slice(2, 7);
      set((s) => ({ toasts: [...s.toasts, { id, text, kind }] }));
      setTimeout(() => set((s) => ({ toasts: s.toasts.filter((t) => t.id !== id) })), 3200);
    };

    // generic CRUD
    const add = (key, row) => set((s) => ({ [key]: [row, ...s[key]] }));
    const update = (key, id, patch) =>
      set((s) => ({ [key]: s[key].map((r) => (r.id === id ? { ...r, ...patch } : r)) }));
    const remove = (key, id) =>
      set((s) => ({ [key]: s[key].filter((r) => r.id !== id) }));

    // Lookups
    const by = (key, id) => state[key]?.find((r) => r.id === id) || null;

    const dismissAlarm = (key) =>
      set((s) => ({ dismissedAlarms: new Set([...s.dismissedAlarms, key]) }));

    // Activity logging
    const logActivity = (entry) =>
      set((s) => ({
        activity: [{ id: 'a-' + Math.random().toString(36).slice(2, 7), ts: new Date().toISOString().slice(0, 19), actor: s.currentUserId, ...entry }, ...s.activity],
      }));

    // Global search
    const search = (q) => {
      if (!q) return [];
      const ql = q.toLowerCase();
      const hit = (s) => s && s.toLowerCase().includes(ql);
      const results = [];
      for (const p of state.reagent_products) {
        if (hit(p.name) || hit(p.code) || hit(p.cat_no)) {
          results.push({ kind: 'reagent_product', id: p.id, title: p.name, sub: `${p.code} · ${state.suppliers.find(x=>x.id===p.supplier_id)?.short}`, route: `#/reagents/products` });
        }
      }
      for (const b of state.reagent_batches) {
        const p = state.reagent_products.find((x) => x.id === b.product_id);
        if (hit(b.lot) || hit(p?.name)) {
          results.push({ kind: 'reagent_batch', id: b.id, title: `${p?.name} · ${b.lot}`, sub: `剩 ${b.on_hand_boxes} 盒 · ${b.location}`, route: `#/reagents/batches/${b.id}` });
        }
      }
      for (const dp of state.device_products) {
        if (hit(dp.name) || hit(dp.model) || hit(dp.brand)) {
          results.push({ kind: 'device_product', id: dp.id, title: dp.name, sub: `${dp.brand} · ${dp.model}`, route: `#/devices/products` });
        }
      }
      for (const u of state.device_units) {
        if (hit(u.sn) || hit(state.device_products.find(x=>x.id===u.product_id)?.name)) {
          const dp = state.device_products.find((x) => x.id === u.product_id);
          results.push({ kind: 'device_unit', id: u.id, title: u.sn || `(SN 缺失) ${dp?.name}`, sub: `${dp?.name} · ${u.status}`, route: `#/devices/units/${u.id}` });
        }
      }
      for (const s of state.suppliers) {
        if (hit(s.name) || hit(s.short) || hit(s.contact)) {
          results.push({ kind: 'supplier', id: s.id, title: s.name, sub: `供货商 · ${s.city} · ${s.contact}`, route: `#/suppliers/${s.id}` });
        }
      }
      for (const c of state.customers) {
        if (hit(c.name) || hit(c.short) || hit(c.contact)) {
          results.push({ kind: 'customer', id: c.id, title: c.name, sub: `客户 · ${c.city} · ${c.contact}`, route: `#/customers/${c.id}` });
        }
      }
      return results.slice(0, 24);
    };

    // Aggregate alarms across the system
    const allAlarms = React.useMemo(() => {
      const out = [];
      for (const b of state.reagent_batches) {
        const p = state.reagent_products.find((x) => x.id === b.product_id);
        for (const a of window.reagentAlarms(b, p)) {
          out.push({ ...a, scope: 'reagent', entity: b, entityKind: 'batch', product: p, key: `${a.type}:${b.id}` });
        }
      }
      for (const o of state.reagent_outflows) {
        for (const a of window.outflowAlarms(o)) {
          const b = state.reagent_batches.find((x) => x.id === o.batch_id);
          const p = state.reagent_products.find((x) => x.id === b?.product_id);
          out.push({ ...a, scope: 'reagent', entity: o, entityKind: 'outflow', batch: b, product: p, key: `${a.type}:${o.id}` });
        }
      }
      for (const u of state.device_units) {
        for (const a of window.deviceAlarms(u)) {
          const dp = state.device_products.find((x) => x.id === u.product_id);
          out.push({ ...a, scope: 'device', entity: u, entityKind: 'unit', product: dp, key: `${a.type}:${u.id}` });
        }
      }
      return out.sort((x, y) => window.severity(y.type) - window.severity(x.type));
    }, [state.reagent_batches, state.reagent_outflows, state.device_units]);

    const value = {
      ...state, set, add, update, remove, by, search, toast, dismissAlarm, logActivity, allAlarms,
    };
    return <StoreCtx.Provider value={value}>{children}</StoreCtx.Provider>;
  }

  // ===== Hash router =====
  function useRoute() {
    const [hash, setHash] = React.useState(window.location.hash || '#/');
    React.useEffect(() => {
      const on = () => setHash(window.location.hash || '#/');
      window.addEventListener('hashchange', on);
      return () => window.removeEventListener('hashchange', on);
    }, []);
    const path = hash.replace(/^#/, '');
    const parts = path.split('/').filter(Boolean);
    return { path, parts, hash };
  }

  function navigate(path) {
    window.location.hash = path;
  }

  function matchRoute(path, pattern) {
    const pp = path.split('/').filter(Boolean);
    const tp = pattern.split('/').filter(Boolean);
    if (pp.length !== tp.length) return null;
    const params = {};
    for (let i = 0; i < tp.length; i++) {
      if (tp[i].startsWith(':')) params[tp[i].slice(1)] = decodeURIComponent(pp[i]);
      else if (tp[i] !== pp[i]) return null;
    }
    return params;
  }

  Object.assign(window, { StoreProvider, useStore, useRoute, navigate, matchRoute });
})();
