// hydor-ui.jsx — HYDOR shared UI kit. Depends on hydor-engine.js (window.Hydor).
// Exports to window: useHydor, useDerive, Icon, Btn, Modal, Field, Money, Pct,
// Badge, Empty, Toasts/toast, Confirm, Popover, SortHeader, Affix.

const H = window.Hydor;

/* ---- store hooks ---- */
function useHydor() {
  const [, force] = React.useReducer((x) => x + 1, 0);
  React.useEffect(() => H.subscribe(force), []);
  return H.getState();
}
function useDerive() { useHydor(); return H.derive(); }

/* ---- role / capability hooks ---- */
function useMe() { useHydor(); return H.currentUser(); }
function useRole() {
  const s = useHydor();
  const authOn = !!(s.meta.auth && s.meta.auth.enabled);
  const u = H.currentUser();
  return authOn ? (u ? u.role : null) : s.meta.role;
}
function useCan(cap) { return H.can(useRole(), cap); }
// department-aware capability: uses the signed-in user; falls back to role in preview mode
function useCanU(cap) {
  useHydor();
  const u = H.currentUser();
  if (u) return H.canU(u, cap);
  return H.can(useRole(), cap);
}

/* ---- language ---- */
function useLang() {
  const [lang, setLang] = React.useState(() => window.HydorI18n ? window.HydorI18n.getLang() : "en");
  React.useEffect(() => window.HydorI18n ? window.HydorI18n.onChange((l) => setLang(l)) : undefined, []);
  return lang;
}
function LangToggle({ compact }) {
  const lang = useLang();
  if (!window.HydorI18n) return null;
  const toAr = lang !== "ar";
  return (
    <button className="lang-btn" onClick={() => window.HydorI18n.setLang(toAr ? "ar" : "en")}
      title={toAr ? "التبديل إلى العربية" : "Switch to English"}>
      <Icon name="globe" size={14} />
      <span style={{ fontFamily: toAr ? "'IBM Plex Sans Arabic', sans-serif" : "var(--font)" }}>{toAr ? "عربي" : "EN"}</span>
    </button>
  );
}
// gate money figures: show a discreet lock chip to roles without seeMoney
function Locked({ label = "Restricted" }) {
  return <span className="hx-num" style={{ color: "var(--text-3)", fontSize: 12.5, display: "inline-flex", alignItems: "center", gap: 5 }}><Icon name="lock" size={12} />{label}</span>;
}

/* ---- file-sync status hook ---- */
function useFS() {
  const [st, setSt] = React.useState(() => (window.HydorFS ? window.HydorFS.getStatus() : { supported: false, connected: false }));
  React.useEffect(() => { if (window.HydorFS) return window.HydorFS.onStatus((s) => setSt({ ...s })); }, []);
  return st;
}

/* ---- icon set (feather-style line icons) ---- */
const ICONS = {
  dashboard: "M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z",
  box: "M21 8l-9-5-9 5 9 5 9-5zM3 8v8l9 5 9-5V8M12 13v8",
  ledger: "M4 3h12l4 4v14H4zM16 3v4h4M8 11h8M8 15h8M8 19h5",
  cost: "M12 1v22M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6",
  people: "M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2M9 11a4 4 0 100-8 4 4 0 000 8zM22 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75",
  money: "M2 6h20v12H2zM12 9a3 3 0 100 6 3 3 0 000-6zM6 9v.01M18 15v.01",
  report: "M4 3h16v18H4zM8 13v4M12 9v8M16 11v6",
  activity: "M22 12h-4l-3 9L9 3l-3 9H2",
  settings: "M12 15a3 3 0 100-6 3 3 0 000 6zM19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 11-2.83 2.83l-.06-.06a1.65 1.65 0 00-2.81 1.17V21a2 2 0 01-4 0v-.09A1.65 1.65 0 006.6 19.4l-.06.06a2 2 0 11-2.83-2.83l.06-.06a1.65 1.65 0 00-1.17-2.81H2a2 2 0 010-4h.09A1.65 1.65 0 003.7 6.6l-.06-.06a2 2 0 112.83-2.83l.06.06A1.65 1.65 0 009 3.7V2a2 2 0 014 0v.09a1.65 1.65 0 002.81 1.17l.06-.06a2 2 0 112.83 2.83l-.06.06A1.65 1.65 0 0021 9h.09a2 2 0 010 4H21a1.65 1.65 0 00-1.6 2z",
  plus: "M12 5v14M5 12h14",
  search: "M11 19a8 8 0 100-16 8 8 0 000 16zM21 21l-4.35-4.35",
  bell: "M18 8a6 6 0 00-12 0c0 7-3 9-3 9h18s-3-2-3-9M13.73 21a2 2 0 01-3.46 0",
  x: "M18 6L6 18M6 6l12 12",
  edit: "M11 4H4v16h16v-7M18.5 2.5a2.12 2.12 0 013 3L12 15l-4 1 1-4 9.5-9.5z",
  trash: "M3 6h18M19 6v14H5V6M8 6V4h8v2M10 11v6M14 11v6",
  check: "M20 6L9 17l-5-5",
  download: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3",
  upload: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12",
  warn: "M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0zM12 9v4M12 17h.01",
  filter: "M22 3H2l8 9.46V19l4 2v-8.54L22 3z",
  print: "M6 9V2h12v7M6 18H4a2 2 0 01-2-2v-5a2 2 0 012-2h16a2 2 0 012 2v5a2 2 0 01-2 2h-2M6 14h12v8H6z",
  lock: "M19 11H5a2 2 0 00-2 2v7a2 2 0 002 2h14a2 2 0 002-2v-7a2 2 0 00-2-2zM7 11V7a5 5 0 0110 0v4",
  unlock: "M19 11H5a2 2 0 00-2 2v7a2 2 0 002 2h14a2 2 0 002-2v-7a2 2 0 00-2-2zM7 11V7a5 5 0 019.9-1",
  arrow: "M5 12h14M12 5l7 7-7 7",
  chart: "M18 20V10M12 20V4M6 20v-6",
  layers: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5",
  zap: "M13 2L3 14h9l-1 8 10-12h-9l1-8z",
  user: "M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2M12 11a4 4 0 100-8 4 4 0 000 8z",
  refresh: "M23 4v6h-6M1 20v-6h6M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15",
  tag: "M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82zM7 7h.01",
  alert: "M12 9v4M12 17h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z",
  save: "M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2zM17 21v-8H7v8M7 3v5h8",
  database: "M12 2C7 2 3 3.34 3 5s4 3 9 3 9-1.34 9-3-4-3-9-3zM3 5v7c0 1.66 4 3 9 3s9-1.34 9-3V5M3 12v7c0 1.66 4 3 9 3s9-1.34 9-3v-7",
  target: "M12 12m-9 0a9 9 0 1018 0 9 9 0 10-18 0M12 12m-5 0a5 5 0 1010 0 5 5 0 10-10 0M12 12m-1 0a1 1 0 102 0 1 1 0 10-2 0",
  phone: "M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72c.13.96.36 1.9.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0122 16.92z",
  calendar: "M19 4H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2zM16 2v4M8 2v4M3 10h18",
  briefcase: "M20 7H4a2 2 0 00-2 2v10a2 2 0 002 2h16a2 2 0 002-2V9a2 2 0 00-2-2zM16 21V5a2 2 0 00-2-2h-4a2 2 0 00-2 2v16",
  compass: "M12 22a10 10 0 100-20 10 10 0 000 20zM16.24 7.76l-2.12 6.36-6.36 2.12 2.12-6.36 6.36-2.12z",
  award: "M12 15a7 7 0 100-14 7 7 0 000 14zM8.21 13.89L7 23l5-3 5 3-1.21-9.12",
  clock: "M12 22a10 10 0 100-20 10 10 0 000 20zM12 6v6l4 2",
  pin: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0zM12 13a3 3 0 100-6 3 3 0 000 6z",
  heart: "M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z",
  share: "M4 12v8a2 2 0 002 2h12a2 2 0 002-2v-8M16 6l-4-4-4 4M12 2v13",
  globe: "M12 22a10 10 0 100-20 10 10 0 000 20zM2 12h20M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z",
};
function Icon({ name, size, style, className }) {
  const d = ICONS[name] || "";
  return (
    <svg className={className} width={size || 18} height={size || 18} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={style}>
      {d.split("M").filter(Boolean).map((seg, i) => <path key={i} d={"M" + seg} />)}
    </svg>
  );
}

/* ---- button ---- */
function Btn({ variant, sm, icon, children, className, ...rest }) {
  const cls = ["btn", variant && "btn-" + variant, sm && "btn-sm", !children && "btn-icon", className].filter(Boolean).join(" ");
  return <button className={cls} {...rest}>{icon && <Icon name={icon} size={sm ? 14 : 15} />}{children}</button>;
}

/* ---- money / pct / qty display ---- */
function Money({ v, dec = 3, unit = false, sign = false, cls = "" }) {
  const neg = v < 0;
  const out = H.fmtMoney(Math.abs(v), dec);
  return <span className={"hx-num " + cls}>{neg ? "−" : sign && v > 0 ? "+" : ""}{out}{unit && <span style={{ color: "var(--text-3)", fontSize: ".82em", marginLeft: 3 }}>JOD</span>}</span>;
}
function Money0({ v, unit }) { return <span className="hx-num">{v < 0 ? "−" : ""}{H.fmtMoney0(Math.abs(v))}{unit && <span style={{ color: "var(--text-3)", fontSize: ".82em", marginLeft: 3 }}>JOD</span>}</span>; }
function Pct({ v, color }) { const c = color ? (v >= 0 ? "hx-pos" : "hx-neg") : ""; return <span className={"hx-num " + c}>{H.fmtPct(v)}</span>; }

/* ---- badge ---- */
function Badge({ color = "gray", dot, children }) { return <span className={"badge " + color + (dot ? " dot" : "")}>{children}</span>; }

/* ---- form field ---- */
function Field({ label, hint, hintWarn, error, children, span2 }) {
  return (
    <div className={"field" + (span2 ? " span2" : "")}>
      {label && <label>{label}</label>}
      {children}
      {error ? <span className="field-hint warn">{error}</span> : hint && <span className={"field-hint" + (hintWarn ? " warn" : "")}>{hint}</span>}
    </div>
  );
}
function Affix({ children, affix }) { return <div className="inp-affix">{children}<span className="affix">{affix}</span></div>; }

/* ---- modal ---- */
function Modal({ title, onClose, children, foot, lg }) {
  React.useEffect(() => {
    const k = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", k); return () => window.removeEventListener("keydown", k);
  }, [onClose]);
  return (
    <div className="scrim" onMouseDown={(e) => e.target === e.currentTarget && onClose()}>
      <div className={"modal" + (lg ? " lg" : "")}>
        <div className="modal-head"><h3>{title}</h3><Btn variant="ghost" icon="x" onClick={onClose} /></div>
        <div className="modal-body">{children}</div>
        {foot && <div className="modal-foot">{foot}</div>}
      </div>
    </div>
  );
}

/* ---- confirm dialog ---- */
function Confirm({ title, body, danger, confirmLabel = "Confirm", onConfirm, onClose }) {
  return (
    <Modal title={title} onClose={onClose} foot={<>
      <Btn variant="ghost" onClick={onClose}>Cancel</Btn>
      <Btn variant={danger ? "danger" : "primary"} onClick={() => { onConfirm(); onClose(); }}>{confirmLabel}</Btn>
    </>}>
      <p style={{ margin: 0, fontSize: 14, color: "var(--text-2)", lineHeight: 1.6 }}>{body}</p>
    </Modal>
  );
}

/* ---- empty state ---- */
function Empty({ icon = "box", title, children, action }) {
  return (
    <div className="empty">
      <div className="empty-icon"><Icon name={icon} size={26} /></div>
      <h3>{title}</h3>
      {children && <p>{children}</p>}
      {action}
    </div>
  );
}

/* ---- sortable header cell ---- */
function SortHeader({ col, label, sort, setSort, r }) {
  const active = sort.key === col;
  return (
    <th className={"sortable" + (r ? " r" : "")} onClick={() => setSort({ key: col, dir: active && sort.dir === "asc" ? "desc" : "asc" })}>
      {label}{active && <span className="sort-ar">{sort.dir === "asc" ? "▲" : "▼"}</span>}
    </th>
  );
}
function sortRows(rows, sort, accessors) {
  if (!sort.key) return rows;
  const get = accessors[sort.key] || ((r) => r[sort.key]);
  const out = rows.slice().sort((a, b) => {
    const av = get(a), bv = get(b);
    if (typeof av === "number" && typeof bv === "number") return av - bv;
    return String(av).localeCompare(String(bv));
  });
  return sort.dir === "desc" ? out.reverse() : out;
}

/* ---- popover ---- */
function Popover({ open, onClose, children, style }) {
  const ref = React.useRef();
  React.useEffect(() => {
    if (!open) return;
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
    setTimeout(() => document.addEventListener("mousedown", h), 0);
    return () => document.removeEventListener("mousedown", h);
  }, [open, onClose]);
  if (!open) return null;
  return <div className="pop" ref={ref} style={style}>{children}</div>;
}

/* ---- toast system ---- */
const ToastCtx = React.createContext(() => {});
function useToast() { return React.useContext(ToastCtx); }
function ToastHost({ children }) {
  const [items, setItems] = React.useState([]);
  const push = React.useCallback((msg, kind = "ok") => {
    const id = Math.random();
    setItems((x) => [...x, { id, msg, kind }]);
    setTimeout(() => setItems((x) => x.filter((i) => i.id !== id)), kind === "err" ? 5200 : 2800);
  }, []);
  return (
    <ToastCtx.Provider value={push}>
      {children}
      <div className="toast-wrap">
        {items.map((i) => (
          <div key={i.id} className={"toast " + i.kind}>
            <Icon name={i.kind === "err" ? "warn" : "check"} size={16} style={{ color: i.kind === "err" ? "var(--neg)" : "var(--pos)", flex: "none" }} />
            <span>{i.msg}</span>
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}

/* employee badge */
function EmpBadge({ code }) { return <span className="hx-emp-badge">{code || "—"}</span>; }

Object.assign(window, {
  useHydor, useDerive, useFS, useRole, useMe, useCan, useCanU, useLang, LangToggle, Locked, Icon, Btn, Money, Money0, Pct, Badge, Field, Affix,
  Modal, Confirm, Empty, SortHeader, sortRows, Popover, ToastHost, useToast, EmpBadge,
});
