/* screen-catalog.jsx — Product & service catalog with stock tracking
 * → window.QScreens.Catalog
 */
(function () {
  const { useState } = React;
  const Q = window.Q, LIB = window.LIB, Icons = window.Icons;
  const { Icon } = Icons;
  const { AppBar, Card, Money, Kicker, Button, EmptyState, IconButton, Sheet, Field, Input, Select, Segmented, Toggle, Stepper } = Q;
  const t = window.t;
  /* Soft translate: renders the string only if the key resolves to real copy.
     Lane 7 owns strings.js; until a referenced key lands, tg returns "" so a
     raw key never leaks into the UI. */
  const tg = (key, vars) => { const s = t(key, vars); return s === key ? "" : s; };

  const KIND_ICON = { product: "package", service: "briefcase" };
  const TAX_FALLBACK = [
    { name: "VAT", rate: 0 }, { name: "VAT", rate: 5.5 }, { name: "VAT", rate: 10 }, { name: "VAT", rate: 20 },
  ];

  /* Tax options flow from db.config.taxes (single source of truth, shared with
     editor.jsx + Settings) instead of a hardcoded [0,5.5,10,20]. Deduped by
     rate; the item's own rate is appended if a custom value isn't in config so
     editing never silently drops a rate. */
  function taxOptions(db, currentRate) {
    const src = (db.config && db.config.taxes) || (db.COMPANY && db.COMPANY.taxes) || TAX_FALLBACK;
    const seen = new Set();
    const opts = [];
    src.forEach(tx => {
      const r = Number(tx.rate) || 0;
      if (seen.has(r)) return;
      seen.add(r);
      opts.push({ value: String(r), label: tx.name ? `${tx.name} (${LIB.fmtPct(r)})` : LIB.fmtPct(r) });
    });
    const cr = Number(currentRate) || 0;
    if (!seen.has(cr)) opts.push({ value: String(cr), label: LIB.fmtPct(cr) });
    opts.sort((a, b) => Number(a.value) - Number(b.value));
    return opts;
  }

  /* Stock cue (G6): in-stock neutral mono, low → warning, out → error. */
  function StockLabel({ item }) {
    const st = LIB.stockState(item);
    if (st === "none") return <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: "var(--color-text-3)" }}>{t("cat.stock.untracked")}</span>;
    const color = st === "out" ? "var(--color-error)" : st === "low" ? "var(--color-warning)" : "var(--color-text-1)";
    return (
      <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontFamily: "var(--font-mono)", fontSize: 10.5, fontWeight: 600, color, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" }}>
        {st !== "ok" && <span style={{ width: 5, height: 5, borderRadius: "50%", background: "currentColor", flexShrink: 0 }} />}
        {st === "out" ? t("cat.stock.out") : t("cat.stock.in", { n: item.stock })}
      </span>
    );
  }

  /* ── Add / edit item sheet ───────────────────────────────────── */
  function ItemSheet({ api, item, onClose }) {
    const { db, setDb } = api;
    const cur = db.COMPANY.currency;
    const sym = (window.CURRENCIES[cur] || {}).symbol;
    const [f, setF] = useState(() => item ? {
      name: item.name, kind: item.kind || "product", sku: item.sku || "", unit: item.unit || "piece",
      price: String(item.price), taxRate: item.taxRate != null ? item.taxRate : db.COMPANY.taxRate,
      track: item.stock != null, stock: item.stock != null ? item.stock : 0,
      lowStockAt: item.lowStockAt != null ? item.lowStockAt : 5,
    } : {
      name: "", kind: "product", sku: "", unit: "piece",
      price: "", taxRate: db.COMPANY.taxRate, track: false, stock: 0, lowStockAt: 5,
    });
    const up = patch => setF(x => ({ ...x, ...patch }));
    const setKind = k => up({ kind: k, unit: k === "service" ? "day" : "piece", track: k === "service" ? false : f.track });

    const save = () => {
      const tracked = f.kind === "product" && f.track;
      const base = {
        name: f.name.trim(), kind: f.kind, sku: f.kind === "product" ? f.sku.trim() : "",
        unit: f.unit, price: Number(f.price) || 0, taxRate: Number(f.taxRate) || 0, currency: cur,
        stock: tracked ? (Number(f.stock) || 0) : null,
        lowStockAt: tracked ? (Number(f.lowStockAt) || 0) : null,
      };
      if (item) {
        setDb(d => ({ ...d, CATALOG: d.CATALOG.map(x => x.id === item.id ? { ...x, ...base } : x) }));
        Q.toast(t("toast.catalogUpdated", { name: base.name }), "check");
      } else {
        setDb(d => ({ ...d, CATALOG: [...d.CATALOG, { id: LIB.newId("cat"), ...base }] }));
        Q.toast(t("toast.catalogAdded", { name: base.name }), "check");
      }
      onClose();
    };
    const del = () => {
      setDb(d => ({ ...d, CATALOG: d.CATALOG.filter(x => x.id !== item.id) }));
      Q.toast(t("toast.catalogDeleted", { name: item.name }), "trash");
      onClose();
    };
    const addToInvoice = () => {
      onClose();
      api.openManual({ items: [LIB.catalogToLine(item, 1)] });
      Q.toast(t("toast.addedToInvoice"), "invoice");
    };

    return (
      <Sheet open onClose={onClose} height="92%" title={item ? t("cat.edit") : t("cat.add.title")}
        footer={<Button variant="primary" size="lg" full icon="check" disabled={!f.name.trim()} onClick={save}>{t("cat.save")}</Button>}>
        <div style={{ padding: "2px 16px 20px", display: "flex", flexDirection: "column", gap: 14 }}>
          <Field label={t("cat.field.name")}><Input value={f.name} onChange={e => up({ name: e.target.value })} placeholder={t("cat.field.name.ph")} /></Field>
          <div>
            <Kicker style={{ marginBottom: 8 }}>{t("cat.field.kind")}</Kicker>
            <Segmented value={f.kind} onChange={setKind}
              options={[{ value: "product", label: t("cat.kind.product") }, { value: "service", label: t("cat.kind.service") }]} />
          </div>
          <div style={{ display: "flex", gap: 12 }}>
            {f.kind === "product" && (
              <Field label={t("cat.field.sku")} style={{ flex: 1 }}>
                <Input value={f.sku} onChange={e => up({ sku: e.target.value })} mono />
              </Field>
            )}
            <Field label={t("cat.field.unit")} style={{ flex: 1 }}>
              <Select value={f.unit} onChange={e => up({ unit: e.target.value })} options={LIB.UNITS.map(u => ({ value: u.value, label: LIB.unitLabel(u.value, 1) || u.label }))} />
            </Field>
          </div>
          <div style={{ display: "flex", gap: 12 }}>
            <Field label={t("cat.field.price")} style={{ flex: 1.4 }}>
              <div style={{ position: "relative" }}>
                <span style={{ position: "absolute", left: 14, top: "50%", transform: "translateY(-50%)", fontFamily: "var(--font-mono)", fontSize: 15, color: "var(--color-text-3)" }}>{sym}</span>
                <Input value={f.price} onChange={e => up({ price: e.target.value.replace(/[^\d.]/g, "") })} mono inputMode="decimal" style={{ paddingLeft: 34 }} />
              </div>
            </Field>
            <Field label={t("cat.field.tax")} style={{ flex: 1 }}>
              <Select value={String(f.taxRate)} onChange={e => up({ taxRate: Number(e.target.value) })}
                options={taxOptions(db, f.taxRate)} />
            </Field>
          </div>

          {f.kind === "product" ? (
            <div style={{ border: "1.4px solid var(--color-border-strong)", borderRadius: 12, overflow: "hidden" }}>
              <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "13px 14px" }}>
                <div style={{ flex: 1, fontSize: 14, fontWeight: 600 }}>{t("cat.field.track")}</div>
                <Toggle checked={f.track} onChange={v => up({ track: v })} label={t("cat.field.track")} />
              </div>
              {f.track && (
                <div className="q-fade" style={{ display: "flex", gap: 12, padding: "12px 14px 14px", borderTop: "1px solid var(--color-border)" }}>
                  <div style={{ flex: 1 }}>
                    <Kicker style={{ marginBottom: 8 }}>{t("cat.field.stock")}</Kicker>
                    <Stepper value={f.stock} onChange={v => up({ stock: v })} />
                  </div>
                  <div style={{ flex: 1 }}>
                    <Kicker style={{ marginBottom: 8 }}>{t("cat.field.lowstock")}</Kicker>
                    <Stepper value={f.lowStockAt} onChange={v => up({ lowStockAt: v })} />
                  </div>
                </div>
              )}
            </div>
          ) : tg("cat.track.serviceNote") ? (
            /* Services aren't stock-tracked. Rather than silently dropping the
               toggle when the user switches Type → Service, explain why (G6:
               cause→effect feedback, progressive disclosure). */
            <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "11px 14px", background: "var(--color-surface-1)", border: "1.4px solid var(--color-border)", borderRadius: 12 }}>
              <Icon name="alert" size={15} color="var(--color-text-3)" />
              <div style={{ flex: 1, fontSize: 12.5, color: "var(--color-text-2)", lineHeight: 1.35 }}>{tg("cat.track.serviceNote")}</div>
            </div>
          ) : null}

          {item && (
            <div style={{ display: "flex", flexDirection: "column", gap: 10, paddingTop: 4 }}>
              <Button variant="secondary" size="md" full icon="invoice" onClick={addToInvoice}>{t("cat.addtoinvoice")}</Button>
              <Button variant="ghost" size="md" full icon="trash" style={{ color: "var(--color-error)" }} onClick={del}>{t("cat.delete")}</Button>
            </div>
          )}
        </div>
      </Sheet>
    );
  }

  /* ── List ────────────────────────────────────────────────────── */
  function Catalog({ api }) {
    const { db, setDb } = api;
    const [query, setQuery] = useState("");
    const [tab, setTab] = useState("all");
    const [addOpen, setAddOpen] = useState(false);
    const [editItem, setEditItem] = useState(null);

    const delItem = it => {
      setDb(d => ({ ...d, CATALOG: d.CATALOG.filter(x => x.id !== it.id) }));
      Q.toast(t("toast.catalogDeleted", { name: it.name }), "trash");
    };
    /* Low-stock items are always products — reveal them no matter the current
       tab/search so the warning's CTA actually surfaces the affected rows. */
    const revealLowStock = () => { setQuery(""); setTab("products"); };

    let list = db.CATALOG.slice();
    if (tab !== "all") list = list.filter(it => tab === "products" ? it.kind === "product" : it.kind === "service");
    if (query.trim()) {
      const q = query.toLowerCase();
      list = list.filter(it => it.name.toLowerCase().includes(q) || (it.sku || "").toLowerCase().includes(q));
    }
    const low = LIB.lowStock(db.CATALOG);
    const isEmpty = db.CATALOG.length === 0;

    return (
      <div style={{ paddingBottom: 4 }}>
        <AppBar large title={t("cat.title")} onBack={() => api.back()} kicker={t("cat.sub", { count: db.CATALOG.length })}
          right={<IconButton name="plus" label={t("cat.new")} onClick={() => setAddOpen(true)} />} />
        <div style={{ padding: "6px 16px 0", display: "flex", flexDirection: "column", gap: 12 }}>

          {!isEmpty && (
            <label style={{ display: "flex", alignItems: "center", gap: 9, height: 42, padding: "0 14px", background: "var(--color-surface-0)", border: "1.4px solid var(--color-border-strong)", borderRadius: 999, cursor: "text" }}>
              <Icon name="search" size={17} color="var(--color-text-3)" />
              <input value={query} onChange={e => setQuery(e.target.value)} placeholder={t("cat.search")}
                onFocus={e => { e.target.parentElement.style.borderColor = "var(--color-primary)"; }}
                onBlur={e => { e.target.parentElement.style.borderColor = "var(--color-border-strong)"; }}
                style={{ flex: 1, height: "100%", border: "none", background: "transparent", outline: "none", fontSize: 14.5, color: "var(--color-text-1)", fontFamily: "var(--font-sans)" }} />
              {query && <button onClick={() => setQuery("")} aria-label={t("g.close")} style={{ border: "none", background: "transparent", color: "var(--color-text-3)", cursor: "pointer", display: "flex", padding: 2 }}><Icon name="x" size={16} /></button>}
            </label>
          )}

          {!isEmpty && (
            <Segmented value={tab} onChange={setTab}
              options={[{ value: "all", label: t("cat.tab.all") }, { value: "products", label: t("cat.tab.products") }, { value: "services", label: t("cat.tab.services") }]} />
          )}

          {/* Low-stock cue (entity state → warning). Account-wide signal: stays
             visible on every tab and during search so an out-of-stock product
             is never hidden by transient UI state. Acting on it clears the
             query and jumps to Products so the affected rows are actually
             shown. */}
          {!isEmpty && low.length > 0 && (
            <div onClick={revealLowStock} role="button" tabIndex={0}
              onKeyDown={e => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); revealLowStock(); } }}
              className="q-tap" style={{ display: "flex", alignItems: "center", gap: 9, padding: "11px 14px", background: "color-mix(in oklab, var(--color-warning) 10%, transparent)", border: "1.4px solid var(--color-warning)", borderRadius: 12, cursor: "pointer" }}>
              <Icon name="alert" size={16} color="var(--color-warning)" />
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13.5, fontWeight: 600 }}>{t("cat.lowstock.title")}</div>
                <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--color-warning)", marginTop: 1 }}>{t("cat.lowstock.count", { count: low.length })}</div>
              </div>
              <Icon name="chevronRight" size={16} color="var(--color-text-3)" />
            </div>
          )}

          {isEmpty ? (
            <EmptyState icon="package" title={t("cat.empty.title")} body={t("cat.empty.body")}
              action={<Button variant="primary" size="md" icon="plus" onClick={() => setAddOpen(true)}>{t("cat.empty.cta")}</Button>} />
          ) : list.length === 0 ? (
            <EmptyState icon="package" title={t("g.nomatch")} body={t("g.trysearch")} />
          ) : (
            <Card pad={0} style={{ overflow: "hidden" }}>
              {list.map((it, i) => (
                <Q.SwipeRow key={it.id} onClick={() => setEditItem(it)} last={i === list.length - 1}
                  actions={[{ icon: "trash", label: t("cat.delete"), tone: "error", onPress: () => delItem(it) }]}>
                  <div style={{ width: 38, height: 38, borderRadius: 11, background: "var(--color-surface-1)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--color-text-3)", flexShrink: 0 }}>
                    <Icon name={KIND_ICON[it.kind] || "package"} size={17} />
                  </div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 14.5, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{it.name}</div>
                    <div style={{ display: "flex", alignItems: "center", gap: 7, marginTop: 2, minWidth: 0 }}>
                      {it.sku && <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: "var(--color-text-3)", flexShrink: 0 }}>{it.sku}</span>}
                      {it.kind === "service"
                        ? <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: "var(--color-text-3)" }}>{t("cat.kind.service")}</span>
                        : <StockLabel item={it} />}
                    </div>
                  </div>
                  <div style={{ textAlign: "right", flexShrink: 0 }}>
                    <Money amount={it.price} currency={it.currency || db.COMPANY.currency} size={14} cents={!Number.isInteger(Number(it.price))} />
                    <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--color-text-3)", marginTop: 2 }}>/ {LIB.unitLabel(it.unit, 1)}</div>
                  </div>
                </Q.SwipeRow>
              ))}
            </Card>
          )}
        </div>

        {(addOpen || editItem) && <ItemSheet api={api} item={editItem} onClose={() => { setAddOpen(false); setEditItem(null); }} />}
      </div>
    );
  }

  window.QScreens = Object.assign(window.QScreens || {}, { Catalog });
})();
