/* =============================================================
   KASDAP ONE — STORE  (auth · mode · cart · pricing · routing)
   Acts as a mock backend persisted to localStorage.
============================================================= */
const { createContext, useContext, useState, useEffect, useMemo, useCallback, useRef } = React;

const LS = 'kasdap.v1.';
const load = (k, d) => { try { const v = localStorage.getItem(LS + k); return v ? JSON.parse(v) : d; } catch { return d; } };
const save = (k, v) => { try { localStorage.setItem(LS + k, JSON.stringify(v)); } catch {} };

/* ---- deterministic hash for stable "random" attributes ---- */
function hash(str) { let h = 2166136261; for (let i = 0; i < str.length; i++) { h ^= str.charCodeAt(i); h = Math.imul(h, 16777619); } return (h >>> 0); }

/* ---- default tier / pricing config (admin-editable) ---- */
const DEFAULT_PRICING = {
  d2cDiscount: 0.08,                 // retail online discount off MRP
  margins: { distributor: 0.42, chemist: 0.30, hospital: 0.36 }, // off-MRP wholesale margin
  slabs: [ { min: 10, off: 0.03 }, { min: 25, off: 0.05 }, { min: 50, off: 0.08 } ], // extra B2B qty discounts (boxes)
  gst: 0.12,
};

/* ---- seed users (demo credentials shown on login) ---- */
const SEED_USERS = [
  { id: 'u-dist',  name: 'Rajesh Distributors', email: 'distributor@kasdap.in', pass: 'demo', role: 'distributor', accountType: 'b2b', modes: ['b2b'], org: 'Rajesh Pharma Distributors', city: 'Mumbai', gst: '27AAACR1111B1Z2' },
  { id: 'u-chem',  name: 'Apollo Chemist', email: 'chemist@kasdap.in', pass: 'demo', role: 'chemist', accountType: 'b2b', modes: ['b2b'], org: 'Apollo Medical Store', city: 'Nagpur', gst: '27AAFCA2222C1Z9' },
  { id: 'u-hosp',  name: 'Sahyadri Hospital', email: 'hospital@kasdap.in', pass: 'demo', role: 'hospital', accountType: 'b2b', modes: ['b2b'], org: 'Sahyadri Multispecialty', city: 'Pune', gst: '27AAGCS3333D1Z4' },
];

/* ---- company admin (separate OTP-gated console, NOT a customer account) ---- */
const ADMIN_EMAIL = 'kasdapweb@gmail.com';

const ROLE_META = {
  distributor: { label: 'Distributor', modes: ['b2b','d2c'], tier: 'distributor', short: 'DS' },
  chemist:     { label: 'Chemist / Retailer', modes: ['b2b','d2c'], tier: 'chemist', short: 'CH' },
  hospital:    { label: 'Stockist', modes: ['b2b','d2c'], tier: 'hospital', short: 'ST' },
  retail:      { label: 'Retail Customer', modes: ['d2c'], tier: 'retail', short: 'RT' },
};
const ACCOUNT_MODES = { d2c: ['d2c'], b2b: ['b2b'], both: ['b2b','d2c'] };

/* ---- parse packing string -> packs per box ---- */
function packsPerBox(packing) {
  if (!packing) return 10;
  const m = String(packing).match(/(\d+)\s*[xX]\s*(\d+)/);
  if (m) return parseInt(m[1]) || 10;
  return 10;
}
function unitsPerPack(packing) {
  const m = String(packing).match(/(\d+)\s*[xX]\s*(\d+)/);
  if (m) return parseInt(m[2]) || 10;
  return 10;
}

const CATEGORY_ICON = {
  'Cardio-Diabetic': 'heart', 'CNS & Neuro': 'brain', 'Renal & Urology': 'droplet',
  'Pain, Ortho & Rheumatology': 'bone', 'Respiratory & Allergy': 'lungs',
  'Gastro & Nutritional': 'stomach', 'Specialty & Advanced': 'spark',
  'Anti-Infective': 'shield', "Women's & Hormonal": 'venus',
};

const StoreCtx = createContext(null);
const useStore = () => useContext(StoreCtx);

// module-level OTP store for password reset (local/offline mode, not persisted)
const _resetOtps = {};

/* enrich a raw catalogue row into a full product object */
function enrichProduct(p) {
  const h = hash(p.handle || p.name || Math.random().toString());
  const ppb = packsPerBox(p.packing);
  const upp = unitsPerPack(p.packing);
  const rating = (3.9 + ((h % 11) / 10)).toFixed(1);
  const reviews = 6 + (h % 240);
  const stock = p.qty != null ? p.qty : (20 + (h % 400));
  return {
    ...p,
    id: p.handle,
    category: p.mainCat || 'Specialty & Advanced',
    icon: CATEGORY_ICON[p.mainCat] || 'spark',
    ppb, upp, rating, reviews, stock,
    rx: !/(VITAMIN|NUTRITION|PRE PRO|SUPPLIMENT)/i.test(p.therapeutic || ''),
    isNew: (h % 9) === 0, hot: (h % 7) === 0, h,
  };
}

function StoreProvider({ children }) {
  /* ---------- base catalogue (from real data file) ---------- */
  const baseProducts = useMemo(() => (window.KASDAP_PRODUCTS || []).map(enrichProduct), []);

  /* ---------- admin catalogue patches (persisted) ---------- */
  const [patches, setPatches]   = useState(() => load('patches', {}));   // handle -> partial fields {stock,image,mrp,name,...}
  const [removed, setRemoved]   = useState(() => load('removed', []));   // [handle]
  const [extras, setExtras]     = useState(() => load('extras', []));    // [rawProduct] added by admin

  const products = useMemo(() => {
    const rm = new Set(removed);
    const base = baseProducts.filter(p => !rm.has(p.id)).map(p => {
      const patch = patches[p.id];
      return patch ? enrichProduct({ ...p, ...patch }) : p;
    });
    const add = extras.filter(e => !rm.has(e.handle)).map(e => enrichProduct(patches[e.handle] ? { ...e, ...patches[e.handle] } : e));
    return [...add, ...base];
  }, [baseProducts, patches, removed, extras]);

  const productById = useMemo(() => { const m = {}; products.forEach(p => m[p.id] = p); return m; }, [products]);

  /* facets */
  const facets = useMemo(() => {
    const cat = {}, ther = {}, type = {};
    products.forEach(p => { cat[p.category] = (cat[p.category]||0)+1; ther[p.therapeutic]=(ther[p.therapeutic]||0)+1; type[p.type]=(type[p.type]||0)+1; });
    const sortE = o => Object.entries(o).sort((a,b)=>b[1]-a[1]);
    return { categories: sortE(cat), therapeutic: sortE(ther), types: sortE(type) };
  }, [products]);

  /* ---------- persisted state ---------- */
  const [theme, setTheme] = useState(() => load('theme', 'dark'));
  const [mode, setModeRaw] = useState(() => { const m = load('mode', 'b2b'); return m === 'd2c' ? 'b2b' : m; });
  const [user, setUser] = useState(() => load('user', null));
  const [cart, setCart] = useState(() => load('cart', []));   // {handle, qty, mode}
  const [pricing, setPricing] = useState(() => load('pricing', DEFAULT_PRICING));
  const [overrides, setOverrides] = useState(() => load('overrides', {})); // handle -> {mrp, d2c, distributor, chemist, hospital}
  const [orders, setOrders] = useState(() => load('orders', []));
  const [users, setUsers] = useState(() => load('users', SEED_USERS));
  const [adminAuthed, setAdminAuthed] = useState(() => load('adminAuthed', false));
  const [route, setRoute] = useState(() => {
    if (!user) return { name: 'login', params: {} };
    const saved = load('route', null);
    if (saved && saved.name && saved.name !== 'login') return saved;
    return { name: 'catalog', params: {} };
  });
  const [toasts, setToasts] = useState([]);

  useEffect(() => save('patches', patches), [patches]);
  useEffect(() => save('removed', removed), [removed]);
  useEffect(() => save('extras', extras), [extras]);
  useEffect(() => save('adminAuthed', adminAuthed), [adminAuthed]);

  useEffect(() => { document.documentElement.dataset.theme = theme; save('theme', theme); }, [theme]);
  useEffect(() => { document.documentElement.dataset.mode = mode; save('mode', mode); }, [mode]);
  useEffect(() => save('user', user), [user]);
  useEffect(() => save('cart', cart), [cart]);
  useEffect(() => save('pricing', pricing), [pricing]);
  useEffect(() => save('overrides', overrides), [overrides]);
  useEffect(() => save('orders', orders), [orders]);
  useEffect(() => save('users', users), [users]);

  /* ---------- live backend hydration (no-op in demo mode) ---------- */
  useEffect(() => {
    if (window.KASDAP_SETTINGS) {
      if (window.KASDAP_SETTINGS.pricing) setPricing(window.KASDAP_SETTINGS.pricing);
      if (window.KASDAP_SETTINGS.theme) applyThemeColors(window.KASDAP_SETTINGS.theme);
    }
  }, []);
  useEffect(() => {
    if (window.KasdapAPI && window.KasdapAPI.live && user) {
      window.KasdapAPI.listOrders().then(({ orders }) => { if (Array.isArray(orders)) setOrders(orders); }).catch(() => {});
    }
  }, [user]);

  /* ---------- admin: wire 401 auto-logout (token expired) ---------- */
  useEffect(() => {
    if (window.KasdapAPI) {
      window.KasdapAPI.onAdminUnauthorized = () => {
        window.KasdapAPI.setAdminToken(null);
        setAdminAuthed(false);
      };
    }
  }, []);

  /* ---------- toast ---------- */
  const toast = useCallback((msg, kind = 'info') => {
    const id = Math.random().toString(36).slice(2);
    setToasts(t => [...t, { id, msg, kind }]);
    setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 3200);
  }, []);

  /* ---------- routing ---------- */
  const go = useCallback((name, params = {}) => { const r = { name, params }; setRoute(r); if (name !== 'login') save('route', r); window.scrollTo(0, 0); }, []);

  /* ---------- auth ---------- */
  const roleMeta = (r) => ROLE_META[r] || ROLE_META.retail;
  const userModes = (u) => (u && u.modes && u.modes.length) ? u.modes : ['b2b'];
  const login = useCallback(async (email, pass) => {
    if (window.KasdapAPI && window.KasdapAPI.live) {
      try {
        const { token, user: u } = await window.KasdapAPI.login(email.trim(), pass);
        window.KasdapAPI.setToken(token);
        setUser(u); setModeRaw(userModes(u)[0]); setRoute({ name: 'catalog', params: {} });
        toast(`Welcome back, ${u.name.split(' ')[0]} 👋`, 'ok');
        return { ok: true };
      } catch (e) { return { ok: false, err: e.message }; }
    }
    const u = users.find(x => x.email.toLowerCase() === email.trim().toLowerCase());
    if (!u || u.pass !== pass) return { ok: false, err: 'Invalid email or password' };
    setUser(u);
    setModeRaw(userModes(u)[0]);
    setRoute({ name: 'catalog', params: {} });
    toast(`Welcome back, ${u.name.split(' ')[0]} 👋`, 'ok');
    return { ok: true };
  }, [users, toast]);

  const signup = useCallback(async (data) => {
    if (!data.gst || !data.gst.trim()) return { ok: false, err: 'GST number is required for B2B registration' };
    const GST_RE = /^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}$/i;
    if (!GST_RE.test(data.gst.trim())) return { ok: false, err: 'Invalid GST format — e.g. 27AAACR1234B1Z5' };
    if (!data.drug_license || !data.drug_license.trim()) return { ok: false, err: 'Drug license number is required for B2B registration' };
    if (window.KasdapAPI && window.KasdapAPI.live) {
      try {
        const payload = { name: data.name, email: data.email, password: data.pass,
          accountType: data.accountType || 'b2b', role: data.role, org: data.org || '', city: data.city || '',
          gst: data.gst.trim().toUpperCase(), drug_license: data.drug_license.trim() };
        let result;
        if (data.gstFile || data.dlFile) {
          const fd = new FormData();
          Object.entries(payload).forEach(([k, v]) => fd.append(k, v));
          if (data.gstFile) fd.append('gst_pdf', data.gstFile);
          if (data.dlFile)  fd.append('drug_license_pdf', data.dlFile);
          result = await window.KasdapAPI.signupWithFiles(fd);
        } else {
          result = await window.KasdapAPI.signup(payload);
        }
        if (result.pending) return { ok: true, pending: true, message: result.message };
        if (result.token) {
          window.KasdapAPI.setToken(result.token);
          setUser(result.user); setModeRaw(userModes(result.user)[0]); setRoute({ name: 'catalog', params: {} });
          toast('Account created — welcome to Kasdap ONE', 'ok');
        }
        return { ok: true };
      } catch (e) { return { ok: false, err: e.message }; }
    }
    // Demo / offline mode
    if (users.some(u => u.email.toLowerCase() === data.email.toLowerCase())) return { ok: false, err: 'Email already registered' };
    if (users.some(u => u.gst && u.gst.toUpperCase() === data.gst.trim().toUpperCase())) return { ok: false, err: 'This GST number is already registered' };
    const at = data.accountType || 'b2b';
    const modes = ACCOUNT_MODES[at] || ['b2b'];
    const role = data.role || 'chemist';
    const u = { id: 'u-' + Math.random().toString(36).slice(2, 8), pass: data.pass, accountType: at, modes, role,
                name: data.name, email: data.email, org: data.org || '', city: data.city || '',
                gst: data.gst.trim().toUpperCase(), drug_license: data.drug_license || '' };
    setUsers(us => [...us, u]); setUser(u);
    setModeRaw(modes[0]);
    setRoute({ name: 'catalog', params: {} });
    toast('Account created — welcome to Kasdap ONE', 'ok');
    return { ok: true };
  }, [users, toast]);

  const logout = useCallback(() => { if (window.KasdapAPI) window.KasdapAPI.setToken(null); setUser(null); setRoute({ name: 'login', params: {} }); }, []);

  const setMode = useCallback((m) => {
    const allowed = userModes(user);
    if (!allowed.includes(m)) { toast('Your account can only order in ' + allowed.map(x=>x.toUpperCase()).join(' / '), 'warn'); return; }
    setModeRaw(m);
  }, [user, toast]);

  /* ---------- pricing engine ---------- */
  const priceOf = useCallback((p, m = mode, qtyBoxes = 1) => {
    const ov = overrides[p.id] || p.override || {};
    const mrp = ov.mrp != null ? ov.mrp : p.mrp;
    if (m === 'd2c') {
      const unit = ov.d2c != null ? ov.d2c : Math.round(mrp * (1 - pricing.d2cDiscount) * 100) / 100;
      return { unit, mrp, unitLabel: 'pack', save: Math.max(0, mrp - unit), savePct: Math.round((1 - unit / mrp) * 100) };
    }
    // b2b: per box. base pack wholesale from tier
    const tier = user ? roleMeta(user.role).tier : 'distributor';
    const margin = pricing.margins[tier] != null ? pricing.margins[tier] : 0.40;
    let packPrice = ov[tier] != null ? ov[tier] : mrp * (1 - margin);
    // qty slab on top
    let slab = 0; pricing.slabs.forEach(s => { if (qtyBoxes >= s.min) slab = Math.max(slab, s.off); });
    packPrice = packPrice * (1 - slab);
    const boxPrice = Math.round(packPrice * p.ppb * 100) / 100;
    const packR = Math.round(packPrice * 100) / 100;
    const boxMrp = Math.round(mrp * p.ppb * 100) / 100;
    return { unit: boxPrice, packPrice: packR, mrp, boxMrp, unitLabel: 'box', tier, slab,
             save: Math.max(0, boxMrp - boxPrice), savePct: Math.round((1 - boxPrice / boxMrp) * 100) };
  }, [mode, overrides, pricing, user]);

  /* ---------- cart ---------- */
  const cartLineKey = (handle, m) => handle + '::' + m;
  const addToCart = useCallback((handle, qty = 1, m = mode) => {
    setCart(c => {
      const i = c.findIndex(x => x.handle === handle && x.mode === m);
      if (i >= 0) { const n = [...c]; n[i] = { ...n[i], qty: n[i].qty + qty }; return n; }
      return [...c, { handle, qty, mode: m }];
    });
  }, [mode]);
  const setQty = useCallback((handle, m, qty) => {
    setCart(c => qty <= 0 ? c.filter(x => !(x.handle===handle && x.mode===m)) : c.map(x => (x.handle===handle && x.mode===m) ? { ...x, qty } : x));
  }, []);
  const removeFromCart = useCallback((handle, m) => setCart(c => c.filter(x => !(x.handle===handle && x.mode===m))), []);
  const clearCart = useCallback(() => setCart([]), []);
  const inCart = useCallback((handle, m = mode) => cart.some(x => x.handle === handle && x.mode === m), [cart, mode]);

  const cartDetail = useMemo(() => {
    const lines = cart.map(l => {
      const p = productById[l.handle]; if (!p) return null;
      const pr = priceOf(p, l.mode, l.qty);
      return { ...l, p, pr, lineTotal: pr.unit * l.qty };
    }).filter(Boolean);
    const d2c = lines.filter(l => l.mode === 'd2c');
    const b2b = lines.filter(l => l.mode === 'b2b');
    const sum = arr => arr.reduce((s, l) => s + l.lineTotal, 0);
    const d2cSub = sum(d2c), b2bSub = sum(b2b);
    const subtotal = d2cSub + b2bSub;
    const gst = Math.round(subtotal * pricing.gst * 100) / 100;
    return { lines, d2c, b2b, d2cSub, b2bSub, subtotal, gst, count: lines.length,
             units: lines.reduce((s,l)=>s+l.qty,0), total: subtotal + gst };
  }, [cart, productById, priceOf, pricing.gst]);

  /* ---------- orders ---------- */
  const placeOrder = useCallback((kind, payload) => {
    const seq = (orders.length + 1).toString().padStart(4, '0');
    const id = (kind === 'rfq' ? 'RFQ-' : 'KD-') + new Date().getFullYear() + '-' + seq;
    const order = {
      id, kind, mode: payload.mode, createdAt: Date.now(),
      uid: user ? user.id : null,
      lines: payload.lines.map(l => ({ handle: l.handle, name: l.p.name, qty: l.qty, mode: l.mode, unit: l.pr.unit, unitLabel: l.pr.unitLabel })),
      total: payload.total, status: kind === 'rfq' ? 'quoted' : 'confirmed',
      customer: user ? { name: user.name, org: user.org, city: user.city } : null,
      address: payload.address || null,
      stage: kind === 'rfq' ? 1 : 1,
    };
    setOrders(o => [order, ...o]);
    // sync to backend when live (optimistic local update already done)
    if (window.KasdapAPI && window.KasdapAPI.live) {
      window.KasdapAPI.placeOrder({ kind, mode: order.mode, lines: order.lines, total: order.total, customer: order.customer, address: order.address })
        .then(({ order: saved }) => { if (saved && saved.id) setOrders(os => os.map(o => o === order ? { ...order, id: saved.id, status: saved.status } : o)); })
        .catch(e => console.warn('Order sync failed:', e.message));
    }
    return order;
  }, [orders, user]);

  /* ---------- admin: order lifecycle ---------- */
  const ORDER_STAGES = { order: ['Confirmed','Packed','Shipped','Delivered'], rfq: ['Requested','Quoted','Approved','Dispatched'] };

  /* Optimistic update helper — applies patch locally, calls API, reverts on failure */
  const _adminUpdate = useCallback((id, patch, revert) => {
    setOrders(os => os.map(o => o.id === id ? { ...o, ...patch } : o));
    if (window.KasdapAPI && window.KasdapAPI.live) {
      window.KasdapAPI.adminUpdateOrder(id, patch).catch(() => {
        // Revert local state if API call fails (keeps DB + UI in sync)
        setOrders(os => os.map(o => o.id === id ? { ...o, ...revert } : o));
      });
    }
  }, []);

  const updateOrderStatus = useCallback((id, stage) => {
    setOrders(os => os.map(o => {
      if (o.id !== id) return o;
      const stages = ORDER_STAGES[o.kind] || ORDER_STAGES.order;
      const st = Math.max(1, Math.min(stages.length, stage));
      const statusMap = { order: ['confirmed','packed','shipped','delivered'], rfq: ['requested','quoted','approved','dispatched'] };
      const status = (statusMap[o.kind] || statusMap.order)[st - 1];
      const prev = { stage: o.stage, status: o.status };
      if (window.KasdapAPI && window.KasdapAPI.live) {
        window.KasdapAPI.adminUpdateOrder(id, { stage: st, status }).catch(() => {
          setOrders(os2 => os2.map(x => x.id === id ? { ...x, ...prev } : x));
        });
      }
      return { ...o, stage: st, status };
    }));
  }, []);

  const cancelOrder  = useCallback((id) => {
    _adminUpdate(id, { status: 'cancelled' }, { status: 'confirmed' });
  }, [_adminUpdate]);

  const acceptQuote  = useCallback((id) => {
    setOrders(os => {
      const prev = os.find(o => o.id === id);
      const revert = prev ? { kind: prev.kind, stage: prev.stage, status: prev.status } : {};
      if (window.KasdapAPI && window.KasdapAPI.live) {
        window.KasdapAPI.adminUpdateOrder(id, { kind: 'order', stage: 1, status: 'confirmed', emailType: 'quote_accepted' })
          .catch(() => setOrders(os2 => os2.map(o => o.id === id ? { ...o, ...revert } : o)));
      }
      return os.map(o => o.id === id ? { ...o, kind: 'order', stage: 1, status: 'confirmed' } : o);
    });
  }, []);

  const declineQuote = useCallback((id) => {
    setOrders(os => {
      const prev = os.find(o => o.id === id);
      const revert = prev ? { status: prev.status } : {};
      if (window.KasdapAPI && window.KasdapAPI.live) {
        window.KasdapAPI.adminUpdateOrder(id, { status: 'cancelled', emailType: 'declined' })
          .catch(() => setOrders(os2 => os2.map(o => o.id === id ? { ...o, ...revert } : o)));
      }
      return os.map(o => o.id === id ? { ...o, status: 'cancelled' } : o);
    });
  }, []);

  /* ---------- admin: catalogue bulk ops ---------- */
  const patchProduct  = useCallback((handle, fields) => { if (window.KasdapAPI && window.KasdapAPI.live) window.KasdapAPI.adminEditProduct(handle, fields).catch(()=>{}); setPatches(p => ({ ...p, [handle]: { ...(p[handle]||{}), ...fields } })); }, []);
  const removeProduct = useCallback((handle) => { if (window.KasdapAPI && window.KasdapAPI.live) window.KasdapAPI.adminDeleteProduct(handle).catch(()=>{}); setRemoved(r => r.includes(handle) ? r : [...r, handle]); }, []);
  const addProduct    = useCallback((raw) => {
    const handle = raw.handle || ('sku-' + Math.random().toString(36).slice(2,8));
    if (window.KasdapAPI && window.KasdapAPI.live) window.KasdapAPI.adminAddProduct({ ...raw, handle }).catch(()=>{});
    setExtras(e => [{ ...raw, handle, brand: raw.brand || 'Kasdap' }, ...e]);
    setRemoved(r => r.filter(h => h !== handle));
    return handle;
  }, []);
  /* bulk import: rows = [{handle,name,...}]. mergeMode 'replace' wipes catalogue first (dedupe by handle/SKU). */
  const bulkImport = useCallback((rows, mergeMode) => {
    const seen = new Set(); const clean = [];
    rows.forEach(r => {
      const key = (r.handle || r.sku || r.name || '').toString().toLowerCase().trim();
      if (!key || seen.has(key)) return; seen.add(key);
      clean.push({ ...r, handle: r.handle || ('imp-' + key.replace(/[^a-z0-9]/g,'').slice(0,24)) });
    });
    if (window.KasdapAPI && window.KasdapAPI.live) window.KasdapAPI.adminBulk(clean, mergeMode).catch(()=>{});
    if (mergeMode === 'replace') {
      // replace-all: hide every base product, keep only the imported set live
      setRemoved(baseProducts.map(p => p.id));
      setExtras(clean);
      setPatches({});
    } else {
      setExtras(e => { const map = {}; [...e, ...clean].forEach(x => { map[x.handle] = x; }); return Object.values(map); });
      setRemoved(r => r.filter(h => !clean.some(c => c.handle === h)));
    }
    return { imported: clean.length, skipped: rows.length - clean.length };
  }, [baseProducts]);
  const restoreCatalogue = useCallback(() => { setRemoved([]); setExtras([]); setPatches({}); }, []);

  /* ---------- admin: OTP auth (company console) ---------- */
  const otpRef = useRef(null);
  const requestOtp = useCallback(async (email) => {
    if (window.KasdapAPI && window.KasdapAPI.live) {
      try { await window.KasdapAPI.adminOtpRequest(email.trim()); return { ok: true, emailed: true }; }
      catch (e) { return { ok: false, err: e.message }; }
    }
    if (email.trim().toLowerCase() !== ADMIN_EMAIL) return { ok: false, err: 'This email is not authorised for admin access' };
    const code = ('' + Math.floor(100000 + Math.random() * 900000));
    otpRef.current = { code, exp: Date.now() + 5 * 60000, email };
    return { ok: true, code }; // demo mode surfaces the code on-screen; live mode e-mails it
  }, []);
  const verifyOtp = useCallback(async (code, email) => {
    if (window.KasdapAPI && window.KasdapAPI.live) {
      try { const { token } = await window.KasdapAPI.adminOtpVerify((email || ADMIN_EMAIL).trim(), code.trim());
        window.KasdapAPI.setAdminToken(token); setAdminAuthed(true); return { ok: true }; }
      catch (e) { return { ok: false, err: e.message }; }
    }
    const o = otpRef.current;
    if (!o) return { ok: false, err: 'Request a code first' };
    if (Date.now() > o.exp) return { ok: false, err: 'Code expired — request a new one' };
    if (code.trim() !== o.code) return { ok: false, err: 'Incorrect code' };
    setAdminAuthed(true); otpRef.current = null;
    return { ok: true };
  }, []);
  const adminLogout = useCallback(() => { if (window.KasdapAPI) window.KasdapAPI.setAdminToken(null); setAdminAuthed(false); }, []);

  /* ---------- customer: password reset via OTP ---------- */
  const forgotPassword = useCallback(async (email) => {
    if (window.KasdapAPI && window.KasdapAPI.live) {
      try { const r = await window.KasdapAPI.forgotPassword(email.trim()); return { ok: true, code: r.code || null }; }
      catch (e) { return { ok: false, err: e.message }; }
    }
    const u = users.find(x => x.email.toLowerCase() === email.trim().toLowerCase());
    if (!u) return { ok: false, err: 'No account found with this email' };
    const code = Math.floor(100000 + Math.random() * 900000).toString();
    _resetOtps[email.trim().toLowerCase()] = { code, expires: Date.now() + 5 * 60 * 1000 };
    return { ok: true, code }; // demo: show code on screen
  }, [users]);

  const resetPassword = useCallback(async (email, otp, newPass) => {
    if (window.KasdapAPI && window.KasdapAPI.live) {
      try { await window.KasdapAPI.resetPassword(email.trim(), otp.trim(), newPass); return { ok: true }; }
      catch (e) { return { ok: false, err: e.message }; }
    }
    const key = email.trim().toLowerCase();
    const record = _resetOtps[key];
    if (!record) return { ok: false, err: 'No reset code found — request a new one' };
    if (Date.now() > record.expires) { delete _resetOtps[key]; return { ok: false, err: 'Code expired — request a new one' }; }
    if (record.code !== otp.trim()) return { ok: false, err: 'Incorrect reset code' };
    if (newPass.length < 6) return { ok: false, err: 'Password must be at least 6 characters' };
    setUsers(us => us.map(u => u.email.toLowerCase() === key ? { ...u, pass: newPass } : u));
    delete _resetOtps[key];
    return { ok: true };
  }, [users]);
  const loadAdminOrders = useCallback(() => {
    if (window.KasdapAPI && window.KasdapAPI.live) {
      window.KasdapAPI.adminOrders()
        .then(({ orders }) => { if (Array.isArray(orders)) setOrders(orders); })
        .catch(() => {});  // 401 already handled by onAdminUnauthorized in api.js
    }
  }, []);

  /* seed a couple of historical orders once */
  useEffect(() => {
    if (load('seeded', false) || products.length === 0) return;
    const pick = (i) => products[(i * 53) % products.length];
    const demo = [
      { id: 'KD-2026-0006', uid: 'u-dist', kind: 'rfq', mode: 'b2b', status: 'shipped', stage: 3, total: 48200, createdAt: Date.now()-86400000*3, lines:[{handle:pick(7).id,name:pick(7).name,qty:14,mode:'b2b',unit:1820,unitLabel:'box'}], customer:{name:'Rajesh Distributors',org:'Rajesh Pharma',city:'Mumbai'} },
      { id: 'RFQ-2026-0005', uid: 'u-hosp', kind: 'rfq', mode: 'b2b', status: 'quoted', stage: 2, total: 126500, createdAt: Date.now()-86400000*1, lines:[{handle:pick(11).id,name:pick(11).name,qty:40,mode:'b2b',unit:1600,unitLabel:'box'}], customer:{name:'Sahyadri Hospital',org:'Sahyadri',city:'Pune'} },
    ];
    setOrders(o => o.length ? o : demo);
    save('seeded', true);
  }, [products]);

  const resetData = useCallback(() => {
    Object.keys(localStorage).filter(k => k.startsWith(LS)).forEach(k => localStorage.removeItem(k));
    location.reload();
  }, []);

  const value = {
    products, productById, facets, baseProducts,
    theme, setTheme, toggleTheme: () => setTheme(t => t === 'dark' ? 'light' : 'dark'),
    mode, setMode, modeLabel: 'B2B · Trade',
    user, users, setUsers, login, signup, logout, roleMeta, userModes, ROLE_META, SEED_USERS, ACCOUNT_MODES, ADMIN_EMAIL,
    cart, addToCart, setQty, removeFromCart, clearCart, inCart, cartDetail,
    pricing, setPricing, overrides, setOverrides, priceOf, DEFAULT_PRICING,
    orders, placeOrder, resetData, updateOrderStatus, cancelOrder, acceptQuote, declineQuote, ORDER_STAGES,
    patchProduct, removeProduct, addProduct, bulkImport, restoreCatalogue, patches, removed, extras,
    adminAuthed, requestOtp, verifyOtp, adminLogout, loadAdminOrders,
    forgotPassword, resetPassword,
    route, go, toast, toasts,
  };

  return React.createElement(StoreCtx.Provider, { value }, children);
}

Object.assign(window, { StoreProvider, useStore, ROLE_META, CATEGORY_ICON });
