// Shared UI primitives — neumorphic look. All Thai labels.

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ===== Modal =====
function Modal({ open, onClose, title, children, footer, size }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => e.key === "Escape" && onClose && onClose();
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className={"modal-card" + (size === "lg" ? " lg" : "")} onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <div>
            <h3>{title}</h3>
          </div>
          <button className="neu-btn ghost sm" onClick={onClose} aria-label="close">✕</button>
        </div>
        <div className="modal-body">{children}</div>
        {footer && <div className="modal-foot">{footer}</div>}
      </div>
    </div>
  );
}

// ===== Toast =====
const ToastCtx = React.createContext({ push: () => {} });
function useToast() { return React.useContext(ToastCtx); }
function ToastProvider({ children }) {
  const [list, setList] = useState([]);
  const push = useCallback((text, kind = "ok") => {
    const id = Math.random().toString(36).slice(2);
    setList(l => [...l, { id, text, kind }]);
    setTimeout(() => setList(l => l.filter(t => t.id !== id)), 3000);
  }, []);
  return (
    <ToastCtx.Provider value={{ push }}>
      {children}
      <div className="toast-wrap">
        {list.map(t => (
          <div key={t.id} className={"toast " + t.kind}>
            <span className={"dot " + (t.kind === "ok" ? "ok" : "danger")}></span>
            <span>{t.text}</span>
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}

// ===== Stat card =====
function Stat({ label, value, sub, delta, deltaDir = "up", accent }) {
  return (
    <div className="stat-card" style={accent ? { background: "linear-gradient(135deg, var(--accent), var(--accent-2))", color: "#fff" } : null}>
      <div className="label" style={accent ? { color: "rgba(255,255,255,.8)" } : null}>{label}</div>
      <div className="value mono" style={accent ? { color: "#fff" } : null}>{value}</div>
      {sub && <div style={{ color: accent ? "rgba(255,255,255,.8)" : "var(--ink-3)", fontSize: 12, marginTop: 4 }}>{sub}</div>}
      {delta && (
        <div className={"delta " + (deltaDir === "down" ? "down" : "")} style={accent ? { color: "rgba(255,255,255,.95)" } : null}>
          {deltaDir === "down" ? "▼" : "▲"} {delta}
        </div>
      )}
    </div>
  );
}

// ===== Section card =====
function Section({ title, sub, right, children, pad = true }) {
  return (
    <div className="section-card" style={pad ? null : { padding: 0 }}>
      {(title || right) && (
        <div className="head" style={pad ? null : { padding: 22, marginBottom: 0 }}>
          <div>
            {title && <h3>{title}</h3>}
            {sub && <div className="sub">{sub}</div>}
          </div>
          <div>{right}</div>
        </div>
      )}
      <div style={pad ? null : { padding: "0 22px 22px" }}>{children}</div>
    </div>
  );
}

// ===== Sub-tabs sidebar =====
function SubTabs({ items, value, onChange }) {
  return (
    <div className="sub-tabs">
      {items.map(it => (
        <button key={it.id} className={value === it.id ? "active" : ""} onClick={() => onChange(it.id)}>
          {it.ico && <span className="ico">{it.ico}</span>}
          {it.label}
        </button>
      ))}
    </div>
  );
}

// ===== Sparkline (SVG) =====
function Sparkline({ values, height = 40, color, fill = true }) {
  const w = 260, h = height;
  const max = Math.max(...values, 1);
  const step = w / (values.length - 1);
  const pts = values.map((v, i) => [i * step, h - (v / max) * (h - 4) - 2]);
  const d = pts.map((p, i) => (i === 0 ? "M" : "L") + p[0] + "," + p[1]).join(" ");
  const fillD = d + ` L ${w} ${h} L 0 ${h} Z`;
  const c = color || "var(--accent)";
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" height={h} preserveAspectRatio="none">
      {fill && <path d={fillD} fill={c} opacity=".15" />}
      <path d={d} fill="none" stroke={c} strokeWidth="2" />
    </svg>
  );
}

// ===== Donut =====
function Donut({ slices, size = 140 }) {
  const total = slices.reduce((a, s) => a + s.value, 0) || 1;
  const r = size / 2 - 14;
  const c = 2 * Math.PI * r;
  let acc = 0;
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--line)" strokeWidth="14" />
      {slices.map((s, i) => {
        const frac = s.value / total;
        const dash = frac * c;
        const offset = c - acc;
        acc += dash;
        return (
          <circle key={i} cx={size / 2} cy={size / 2} r={r} fill="none"
            stroke={s.color} strokeWidth="14" strokeDasharray={`${dash} ${c - dash}`}
            strokeDashoffset={offset} transform={`rotate(-90 ${size / 2} ${size / 2})`} strokeLinecap="round" />
        );
      })}
    </svg>
  );
}

// ===== Bar chart row =====
function BarRow({ label, value, max, sub, color }) {
  const pct = max ? (value / max) * 100 : 0;
  return (
    <div className="bar-row">
      <div style={{ color: "var(--ink-2)" }}>{label}</div>
      <div className="bar-track">
        <div className="bar-fill" style={{ width: pct + "%", background: color || null }}></div>
      </div>
      <div className="mono" style={{ textAlign: "right", fontWeight: 600 }}>{sub || value}</div>
    </div>
  );
}

// ===== Number input with thousands =====
function NumberInput({ value, onChange, placeholder, prefix }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      {prefix && <span className="mono" style={{ color: "var(--ink-3)" }}>{prefix}</span>}
      <input className="neu-input mono" type="number" value={value} onChange={e => onChange(Number(e.target.value))} placeholder={placeholder} />
    </div>
  );
}

// ===== Confirm =====
function useConfirm() {
  const [state, setState] = useState(null);
  const ask = useCallback((opts) => new Promise(resolve => setState({ ...opts, resolve })), []);
  const node = state ? (
    <Modal open onClose={() => { state.resolve(false); setState(null); }}
      title={state.title}
      footer={<>
        <button className="neu-btn ghost" onClick={() => { state.resolve(false); setState(null); }}>ยกเลิก</button>
        <button className={"neu-btn " + (state.danger ? "danger" : "primary")} onClick={() => { state.resolve(true); setState(null); }}>{state.confirmLabel || "ยืนยัน"}</button>
      </>}
    >
      <p style={{ margin: 0, color: "var(--ink-2)" }}>{state.body}</p>
    </Modal>
  ) : null;
  return { ask, node };
}

// ===== Coin animation (shoot from button to target) =====
function shootCoins(fromEl, count = 8) {
  const rect = fromEl.getBoundingClientRect();
  for (let i = 0; i < count; i++) {
    const coin = document.createElement("div");
    coin.className = "coin";
    coin.textContent = "฿";
    coin.style.left = (rect.left + rect.width / 2 - 14) + "px";
    coin.style.top = (rect.top + rect.height / 2 - 14) + "px";
    document.body.appendChild(coin);
    const tx = (Math.random() - 0.5) * 300;
    const ty = -200 - Math.random() * 200;
    const dur = 700 + Math.random() * 400;
    coin.animate([
      { transform: "translate(0,0) scale(1)", opacity: 1 },
      { transform: `translate(${tx}px, ${ty}px) scale(.7) rotate(${(Math.random() - 0.5) * 540}deg)`, opacity: 0 },
    ], { duration: dur, easing: "cubic-bezier(.25,.9,.5,1)" });
    setTimeout(() => coin.remove(), dur);
  }
}

// ===== Icons (inline SVG, simple) =====
const Ico = {
  dollar: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...p}><line x1="12" y1="1" x2="12" y2="23" /><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" /></svg>,
  bag: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...p}><path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z" /><line x1="3" y1="6" x2="21" y2="6" /><path d="M16 10a4 4 0 0 1-8 0" /></svg>,
  users: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...p}><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" /><circle cx="9" cy="7" r="4" /><path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75" /></svg>,
  shop: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...p}><path d="M3 9l2-5h14l2 5M3 9v11a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1V9M3 9h18" /></svg>,
  phone: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...p}><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13 1.05.37 2.07.72 3.06a2 2 0 0 1-.45 2.11L8 10.09a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c1 .35 2 .59 3.06.72A2 2 0 0 1 22 16.92z" /></svg>,
  cart: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...p}><circle cx="9" cy="21" r="1" /><circle cx="20" cy="21" r="1" /><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6" /></svg>,
  trending: (p) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...p}><polyline points="22 12 18 12 15 21 9 3 6 12 2 12" /></svg>,
  copy: (p) => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...p}><rect x="9" y="9" width="13" height="13" rx="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" /></svg>,
  ticket: (p) => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" {...p}><path d="M2 9V7a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v2a2 2 0 0 0 0 4v2a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-2a2 2 0 0 0 0-4z" /></svg>,
};

// ===== Heat row (calendar-ish) =====
function HeatRow({ data }) {
  const max = Math.max(...data, 1);
  return (
    <div style={{ display: "grid", gridTemplateColumns: `repeat(${data.length}, 1fr)`, gap: 4 }}>
      {data.map((v, i) => (
        <div key={i} title={`Day ${i + 1}: ฿${v.toLocaleString()}`} style={{
          height: 18,
          borderRadius: 5,
          background: `color-mix(in oklab, var(--accent) ${10 + (v / max) * 90}%, var(--bg-2))`,
        }}></div>
      ))}
    </div>
  );
}

Object.assign(window, {
  Modal, ToastProvider, useToast,
  Stat, Section, SubTabs, Sparkline, Donut, BarRow,
  NumberInput, useConfirm, shootCoins, Ico, HeatRow,
});
