/* X-REAL Stock System — UI Kit (shared components) */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ─── Card ─────────────────────────────────────────────────────────────
function Card({ children, style, className = "", onClick, padded = true, clickable = false }) {
  return (
    <div onClick={onClick} className={`xr-card ${clickable ? "xr-clickable" : ""} ${className}`}
      style={{ padding: padded ? undefined : 0, ...style }}>
      {children}
    </div>
  );
}

// ─── Field Group ──────────────────────────────────────────────────────
function FG({ label, hint, children, style }) {
  return (
    <div className="xr-fg" style={style}>
      {label && <label className="xr-label">{label}</label>}
      {children}
      {hint && <div style={{ fontSize: 11, color: "var(--text-3)" }}>{hint}</div>}
    </div>
  );
}

// ─── Button ───────────────────────────────────────────────────────────
function Btn({ children, onClick, variant = "default", size = "md", icon, full, style, disabled, type }) {
  const cls = ["xr-btn",
    variant !== "default" && `xr-btn--${variant}`,
    size !== "md" && `xr-btn--${size}`,
  ].filter(Boolean).join(" ");
  return (
    <button type={type || "button"} onClick={onClick} disabled={disabled} className={cls}
      style={{ width: full ? "100%" : undefined, ...style }}>
      {icon && <Icon name={icon} size={size === "sm" ? 14 : 16}/>}
      {children}
    </button>
  );
}

// ─── Pill / Badge ─────────────────────────────────────────────────────
function Pill({ children, variant = "default", icon, style }) {
  const cls = `xr-pill ${variant !== "default" ? `xr-pill--${variant}` : ""}`;
  return (
    <span className={cls} style={style}>
      {icon && <Icon name={icon} size={11}/>}
      {children}
    </span>
  );
}

function SkuBadge({ sku, style }) {
  return <span className="xr-sku" style={style}>{sku}</span>;
}

function CatBadge({ cat }) {
  if (!cat) return null;
  return (
    <span style={{
      fontSize: 11, fontWeight: 600, color: cat.color,
      background: cat.color + "18",
      borderRadius: "var(--r-sm)", padding: "2px 8px",
      display: "inline-flex", alignItems: "center", gap: 4,
    }}>
      <span style={{ width: 6, height: 6, borderRadius: "50%", background: cat.color }}/>
      {cat.name}
    </span>
  );
}

const LOC_TYPE_META = {
  storage:     { label: "Storage", color: "info",   icon: "warehouse" },
  consignment: { label: "Consignment", color: "purple", icon: "store" },
  event:       { label: "Event", color: "warn",   icon: "flag" },
  outbound:    { label: "Outbound", color: "success", icon: "arrow-up-right" },
};
function LocBadge({ locType }) {
  const t = LOC_TYPE_META[locType] || LOC_TYPE_META.outbound;
  return <Pill variant={t.color} icon={t.icon}>{t.label}</Pill>;
}

// ─── Info / Warn / Empty ──────────────────────────────────────────────
function InfoBanner({ children, variant = "info", icon, style }) {
  const colorMap = {
    info: { bg: "var(--info-bg)", color: "var(--info)", border: "var(--info-border)" },
    warn: { bg: "var(--warn-bg)", color: "var(--warn)", border: "var(--warn-border)" },
    success: { bg: "var(--success-bg)", color: "var(--success)", border: "var(--success-border)" },
    danger: { bg: "var(--danger-bg)", color: "var(--danger)", border: "var(--danger-border)" },
    accent: { bg: "var(--accent-subtle)", color: "var(--accent-hover)", border: "var(--accent-border)" },
  };
  const c = colorMap[variant] || colorMap.info;
  return (
    <div style={{
      background: c.bg, border: `1px solid ${c.border}`, borderRadius: "var(--r-md)",
      padding: "10px 14px", fontSize: 13, color: c.color, marginBottom: 14,
      display: "flex", alignItems: "flex-start", gap: 10, ...style,
    }}>
      {icon && <Icon name={icon} size={16} style={{ flexShrink: 0, marginTop: 1 }}/>}
      <div style={{ flex: 1 }}>{children}</div>
    </div>
  );
}

function EmptyState({ icon = "package", title, hint, action }) {
  return (
    <div className="xr-empty">
      <div style={{ marginBottom: 10 }}>
        <Icon name={icon} size={36} style={{ color: "var(--text-3)" }}/>
      </div>
      <div style={{ fontSize: 14, fontWeight: 600, color: "var(--text-2)", marginBottom: 4 }}>{title}</div>
      {hint && <div style={{ fontSize: 13, color: "var(--text-3)", marginBottom: 16 }}>{hint}</div>}
      {action}
    </div>
  );
}

// ─── DateInput (dd/mm/yyyy) ───────────────────────────────────────────
function DateInput({ value, onChange, placeholder = "dd/mm/yyyy", style }) {
  const [raw, setRaw] = useState(isoToDmy(value));
  useEffect(() => { setRaw(isoToDmy(value)); }, [value]);
  const handleChange = e => {
    let v = e.target.value.replace(/[^0-9/]/g, "");
    if (v.length === 2 && raw.length === 1) v = v + "/";
    if (v.length === 5 && raw.length === 4) v = v + "/";
    if (v.length > 10) v = v.slice(0, 10);
    setRaw(v);
    if (v.length === 10) { const iso = dmyToIso(v); if (iso) onChange(iso); }
    else if (v === "") onChange("");
  };
  const isValid = raw === "" || (raw.length === 10 && dmyToIso(raw));
  return (
    <input className="xr-input" value={raw} onChange={handleChange} placeholder={placeholder}
      style={{ borderColor: isValid ? undefined : "var(--danger-border)", ...style }}/>
  );
}

// ─── ConfirmModal ─────────────────────────────────────────────────────
function ConfirmModal({ msg, sub, danger = true, okLabel, onOk, onCancel }) {
  return (
    <div className="xr-modal-overlay" onClick={e => { if (e.target === e.currentTarget) onCancel(); }}>
      <div className="xr-modal" style={{ padding: 28, textAlign: "center", maxWidth: 380 }}>
        <div style={{
          width: 48, height: 48, borderRadius: 999, margin: "0 auto 14px",
          background: danger ? "var(--danger-bg)" : "var(--warn-bg)",
          color: danger ? "var(--danger)" : "var(--warn)",
          display: "flex", alignItems: "center", justifyContent: "center",
        }}>
          <Icon name="alert" size={22}/>
        </div>
        <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 6 }}>{msg}</div>
        {sub && <div style={{ fontSize: 13, color: "var(--text-2)", marginBottom: 22 }}>{sub}</div>}
        {!sub && <div style={{ marginBottom: 22 }}/>}
        <div style={{ display: "flex", gap: 10, justifyContent: "center" }}>
          <Btn variant="ghost" onClick={onCancel}>ยกเลิก</Btn>
          <Btn variant={danger ? "danger" : "accent"} onClick={onOk} icon="check">
            {okLabel || (danger ? "ยืนยันลบ" : "ยืนยัน")}
          </Btn>
        </div>
      </div>
    </div>
  );
}

// ─── Toast ────────────────────────────────────────────────────────────
function Toast({ msg, type = "ok" }) {
  return (
    <div className={`xr-toast xr-toast--${type}`}>
      <Icon name={type === "err" ? "alert" : "check"} size={16}
        style={{ color: type === "err" ? "var(--danger)" : "var(--success)" }}/>
      <span>{msg}</span>
    </div>
  );
}

// ─── Product Picker (searchable, grouped by category) ─────────────────
function ProductPicker({ products, cats, value, onChange, filterFn, label = "สินค้า", placeholder = "— เลือกสินค้า —" }) {
  const [search, setSearch] = useState("");
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  const sel = products.find(p => p.id === value);
  useEffect(() => {
    const h = e => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  }, []);
  const filtered = products.filter(p => filterFn ? filterFn(p) : true)
    .filter(p => !search || p.sku.toLowerCase().includes(search.toLowerCase()) || p.name.toLowerCase().includes(search.toLowerCase()));
  const byCat = (cats || []).map(c => ({ cat: c, items: filtered.filter(p => p.catId === c.id) }))
    .filter(g => g.items.length > 0);
  return (
    <FG label={label}>
      <div ref={ref} style={{ position: "relative" }}>
        <div onClick={() => setOpen(o => !o)} className="xr-input" style={{
          cursor: "pointer", display: "flex", justifyContent: "space-between", alignItems: "center",
          minHeight: 38,
        }}>
          {sel ? (
            <span style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13 }}>
              <SkuBadge sku={sel.sku}/>
              <span>{sel.name}</span>
              <span style={{ color: "var(--text-3)", fontSize: 11 }}>{sel.unit}</span>
            </span>
          ) : (
            <span style={{ color: "var(--text-3)", fontSize: 13 }}>{placeholder}</span>
          )}
          <Icon name="chevron-down" size={14} style={{ color: "var(--text-3)" }}/>
        </div>
        {open && (
          <div className="xr-fade-in" style={{
            position: "absolute", top: "calc(100% + 4px)", left: 0, right: 0,
            background: "var(--surface)", border: "1px solid var(--border)",
            borderRadius: "var(--r-md)", boxShadow: "var(--sh-lg)",
            zIndex: 200, maxHeight: 340, overflowY: "auto",
          }}>
            <div style={{
              padding: 8, borderBottom: "1px solid var(--border-subtle)",
              position: "sticky", top: 0, background: "var(--surface)", zIndex: 1,
            }}>
              <input autoFocus value={search} onChange={e => setSearch(e.target.value)}
                placeholder="ค้นหา SKU หรือชื่อ…" className="xr-input xr-input--sm"/>
            </div>
            {byCat.map(({ cat, items }) => (
              <div key={cat.id}>
                <div style={{
                  padding: "8px 14px 4px", fontSize: 10, fontWeight: 700,
                  color: cat.color, textTransform: "uppercase", letterSpacing: .6,
                  background: "var(--surface-2)",
                }}>{cat.name}</div>
                {items.map(p => (
                  <div key={p.id} onClick={() => { onChange(p.id); setOpen(false); setSearch(""); }}
                    style={{
                      padding: "10px 14px", cursor: "pointer",
                      display: "flex", alignItems: "center", gap: 10,
                      background: value === p.id ? "var(--accent-subtle)" : undefined,
                      transition: "background var(--dur-fast) var(--ease)",
                    }}
                    onMouseEnter={e => { if (value !== p.id) e.currentTarget.style.background = "var(--surface-2)"; }}
                    onMouseLeave={e => { if (value !== p.id) e.currentTarget.style.background = ""; }}>
                    <SkuBadge sku={p.sku}/>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, color: "var(--text-1)" }}>{p.name}</div>
                      <div style={{ fontSize: 11, color: "var(--text-3)" }}>{p.unit}</div>
                    </div>
                    {value === p.id && <Icon name="check" size={14} style={{ color: "var(--accent)" }}/>}
                  </div>
                ))}
              </div>
            ))}
            {!filtered.length && <div className="xr-empty" style={{ padding: 24 }}>ไม่พบสินค้า</div>}
          </div>
        )}
      </div>
    </FG>
  );
}

// ─── Beep on successful scan (Web Audio, no asset needed) ──────────────
function playBeep() {
  try {
    const Ctx = window.AudioContext || window.webkitAudioContext;
    if (!Ctx) return;
    const ctx = new Ctx();
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.type = "sine"; osc.frequency.value = 1200;
    osc.connect(gain); gain.connect(ctx.destination);
    gain.gain.setValueAtTime(0.35, ctx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.15);
    osc.start(); osc.stop(ctx.currentTime + 0.16);
    setTimeout(() => ctx.close(), 250);
  } catch (e) { /* ignore */ }
}

// ─── ScanBlock (camera + BarcodeDetector + manual input) ────────────────
function ScanBlock({ products, onFound, showToast, scanStreamRef, compact = false }) {
  const [open, setOpen] = useState(false);
  const vidRef = useRef(null);
  const inputRef = useRef(null);
  const streamRef = useRef(null);
  const detectLoopRef = useRef({ stopped: true, lastCode: null, lastTs: 0 });

  const openScan = async () => {
    if (!navigator.mediaDevices?.getUserMedia) {
      showToast("เบราว์เซอร์นี้ไม่รองรับกล้อง (ต้องใช้ HTTPS)", "err");
      return;
    }
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: { ideal: "environment" } },
        audio: false,
      });
      streamRef.current = stream;
      if (scanStreamRef) scanStreamRef.current = stream;
      setOpen(true);
      const hasDetector = typeof window.BarcodeDetector !== "undefined";
      showToast(hasDetector ? "เปิดกล้องแล้ว — เล็งบาร์โค้ดให้อยู่ในกรอบ" : "เปิดกล้องแล้ว — เบราว์เซอร์นี้ไม่รองรับ auto-detect, ใช้ scanner หรือพิมพ์ barcode แทน");
    } catch (e) {
      showToast("ไม่สามารถเปิดกล้องได้: " + (e.message || "permission denied"), "err");
    }
  };

  // Attach stream + start barcode detection loop after video mounts
  useEffect(() => {
    if (!open || !streamRef.current || !vidRef.current) return;
    const v = vidRef.current;
    v.srcObject = streamRef.current;
    v.setAttribute("playsinline", "true");
    v.setAttribute("webkit-playsinline", "true");
    v.muted = true;
    const tryPlay = () => v.play().catch(err => console.warn("[scan] play failed:", err));
    if (v.readyState >= 2) tryPlay();
    else v.onloadedmetadata = tryPlay;
    inputRef.current?.focus();

    // Start BarcodeDetector loop if supported
    if (typeof window.BarcodeDetector === "undefined") return;
    let detector;
    try {
      detector = new window.BarcodeDetector({
        formats: ["ean_13","ean_8","code_128","code_39","upc_a","upc_e","itf","codabar","qr_code"],
      });
    } catch (e) { return; }

    const state = detectLoopRef.current;
    state.stopped = false; state.lastCode = null; state.lastTs = 0;

    const tick = async () => {
      if (state.stopped || !vidRef.current) return;
      if (vidRef.current.readyState >= 2) {
        try {
          const found = await detector.detect(vidRef.current);
          if (found.length) {
            const code = found[0].rawValue;
            const now = Date.now();
            if (code !== state.lastCode || now - state.lastTs > 1800) {
              state.lastCode = code; state.lastTs = now;
              const p = products.find(x => x.barcode === code) ||
                        products.find(x => x.sku.toLowerCase() === code.toLowerCase());
              if (p) {
                playBeep();
                onFound(p.id);
                showToast(`พบ: ${p.name}`);
              } else {
                showToast(`ไม่พบสินค้า: ${code}`, "err");
              }
            }
          }
        } catch (e) { /* keep looping */ }
      }
      if (!state.stopped) setTimeout(tick, 350);
    };
    setTimeout(tick, 500);
    return () => { state.stopped = true; };
  }, [open, products, onFound]);

  const closeScan = () => {
    detectLoopRef.current.stopped = true;
    if (streamRef.current) {
      streamRef.current.getTracks().forEach(t => t.stop());
      streamRef.current = null;
    }
    if (scanStreamRef?.current) {
      scanStreamRef.current.getTracks().forEach(t => t.stop());
      scanStreamRef.current = null;
    }
    if (vidRef.current) vidRef.current.srcObject = null;
    setOpen(false);
  };
  useEffect(() => () => closeScan(), []);

  const handleBC = e => {
    if (e.key !== "Enter") return;
    e.preventDefault();
    const val = e.target.value.trim();
    if (!val) return;
    const p = products.find(x => x.barcode === val) ||
              products.find(x => x.sku.toLowerCase() === val.toLowerCase());
    if (p) { playBeep(); onFound(p.id); e.target.value = ""; showToast(`พบ: ${p.name}`); }
    else showToast("ไม่พบสินค้านี้ในระบบ", "err");
  };

  return (
    <div style={{ marginBottom: 14 }}>
      <div style={{
        border: `1.5px dashed ${open ? "var(--accent)" : "var(--border-strong)"}`,
        borderRadius: "var(--r-md)", padding: open ? 12 : "14px 16px",
        background: open ? "var(--accent-subtle-2)" : "var(--surface-2)",
        transition: "all var(--dur) var(--ease)",
      }}>
        <div onClick={open ? closeScan : openScan} style={{
          cursor: "pointer", display: "flex", alignItems: "center", gap: 10,
        }}>
          <div style={{
            width: 36, height: 36, borderRadius: "var(--r-md)",
            background: open ? "var(--accent)" : "var(--surface)",
            color: open ? "#fff" : "var(--accent)",
            display: "flex", alignItems: "center", justifyContent: "center",
            border: open ? "none" : "1px solid var(--accent-border)",
            transition: "all var(--dur) var(--ease)",
          }}>
            <Icon name="camera" size={18}/>
          </div>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 13, fontWeight: 600, color: open ? "var(--accent-hover)" : "var(--text-1)" }}>
              {open ? "กล้องเปิดอยู่ — แตะเพื่อปิด" : "สแกน Barcode ด้วยกล้อง"}
            </div>
            <div style={{ fontSize: 11, color: "var(--text-3)" }}>
              {open ? "หรือพิมพ์ barcode ในช่องด้านล่าง" : "ใช้กล้องมือถือ หรือพิมพ์ barcode/SKU"}
            </div>
          </div>
        </div>
        {open && (
          <video ref={vidRef} autoPlay playsInline muted className="xr-fade-in"
            style={{
              width: "100%", maxHeight: 180, borderRadius: "var(--r-sm)",
              objectFit: "cover", marginTop: 10, background: "#000",
            }}/>
        )}
      </div>
      <input ref={inputRef} className="xr-input" placeholder="พิมพ์ barcode หรือ SKU แล้วกด Enter"
        onKeyDown={handleBC} autoComplete="off" style={{ marginTop: 8 }}/>
    </div>
  );
}

// ─── Segmented control ────────────────────────────────────────────────
function Segmented({ options, value, onChange, style }) {
  return (
    <div style={{
      display: "inline-flex", padding: 3, gap: 2,
      background: "var(--surface-3)", borderRadius: "var(--r-md)",
      ...style,
    }}>
      {options.map(opt => (
        <button key={opt.value} onClick={() => onChange(opt.value)} style={{
          padding: "6px 14px", borderRadius: "calc(var(--r-md) - 2px)",
          fontSize: 12.5, fontWeight: 600,
          background: value === opt.value ? "var(--surface)" : "transparent",
          color: value === opt.value ? "var(--text-1)" : "var(--text-2)",
          boxShadow: value === opt.value ? "var(--sh-xs)" : "none",
          transition: "all var(--dur) var(--ease)",
          display: "flex", alignItems: "center", gap: 6,
        }}>
          {opt.icon && <Icon name={opt.icon} size={13}/>}
          {opt.label}
        </button>
      ))}
    </div>
  );
}

// ─── Stat card (KPI tile) ─────────────────────────────────────────────
function StatCard({ label, value, sub, icon, accent = "default", trend, onClick }) {
  const colorMap = {
    default: "var(--text-1)",
    accent: "var(--accent)",
    success: "var(--success)",
    danger: "var(--danger)",
    info: "var(--info)",
    warn: "var(--warn)",
    purple: "var(--purple)",
  };
  return (
    <Card onClick={onClick} clickable={!!onClick}>
      <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", marginBottom: 8 }}>
        <span className="xr-label">{label}</span>
        {icon && (
          <div style={{
            width: 28, height: 28, borderRadius: 8,
            background: `color-mix(in oklab, ${colorMap[accent]} 12%, transparent)`,
            color: colorMap[accent],
            display: "flex", alignItems: "center", justifyContent: "center",
          }}>
            <Icon name={icon} size={15}/>
          </div>
        )}
      </div>
      <div style={{
        fontSize: 28, fontWeight: 700, lineHeight: 1.05, color: colorMap[accent],
        fontVariantNumeric: "tabular-nums",
      }}>{value}</div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 6 }}>
        {sub && <span style={{ fontSize: 11.5, color: "var(--text-3)" }}>{sub}</span>}
        {trend != null && (
          <span style={{
            fontSize: 11, fontWeight: 600,
            color: trend > 0 ? "var(--success)" : trend < 0 ? "var(--danger)" : "var(--text-3)",
            display: "inline-flex", alignItems: "center", gap: 2,
          }}>
            {trend !== 0 && <Icon name={trend > 0 ? "trend-up" : "trend-down"} size={11}/>}
            {trend > 0 ? "+" : ""}{trend}%
          </span>
        )}
      </div>
    </Card>
  );
}

Object.assign(window, {
  Card, FG, Btn, Pill, SkuBadge, CatBadge, LocBadge, LOC_TYPE_META,
  InfoBanner, EmptyState, DateInput, ConfirmModal, Toast,
  ProductPicker, ScanBlock, Segmented, StatCard,
});
