/* ============================================================
   FacilityOS — UI Primitives & Charts
   ============================================================ */

/* ---------- tone helpers ---------- */
function tone(token) { return `var(${token})`; }
function tint(token, pct) { return `color-mix(in oklch, var(${token}) ${pct}%, var(--surface))`; }

/* ---------- Card ---------- */
function Card({ children, style, className = "", pad = true, onClick, hover }) {
  return (
    <div
      onClick={onClick}
      className={"card " + className}
      style={{
        background: "var(--surface)",
        border: "1px solid var(--border)",
        borderRadius: "var(--radius)",
        boxShadow: "var(--shadow-sm)",
        padding: pad ? "calc(var(--pad) * 1.25)" : 0,
        cursor: onClick ? "pointer" : "default",
        ...style,
      }}
      onMouseEnter={hover ? (e) => { e.currentTarget.style.boxShadow = "var(--shadow-md)"; e.currentTarget.style.borderColor = "var(--border-strong)"; } : undefined}
      onMouseLeave={hover ? (e) => { e.currentTarget.style.boxShadow = "var(--shadow-sm)"; e.currentTarget.style.borderColor = "var(--border)"; } : undefined}
    >
      {children}
    </div>
  );
}

/* ---------- Badge (status) ---------- */
function StatusBadge({ status }) {
  const s = window.DB.STATUS[status] || { label: status, token: "--c-low" };
  return (
    <span className="badge" style={{
      display: "inline-flex", alignItems: "center", gap: 6,
      padding: "3px 10px", borderRadius: 999, fontSize: 12, fontWeight: 600,
      color: tone(s.token), background: tint(s.token, 14),
      border: `1px solid ${tint(s.token, 30)}`, whiteSpace: "nowrap",
    }}>
      <span style={{ width: 6, height: 6, borderRadius: 99, background: tone(s.token) }} />
      {s.label}
    </span>
  );
}

/* ---------- Priority pill ---------- */
function PriorityPill({ priority, dot = false }) {
  const p = window.DB.PRIORITY[priority] || { label: priority, token: "--c-low" };
  if (dot) {
    return (
      <span style={{ display: "inline-flex", alignItems: "center", gap: 7, fontSize: 13, fontWeight: 500, color: "var(--text)" }}>
        <span style={{ width: 8, height: 8, borderRadius: 99, background: tone(p.token), boxShadow: `0 0 0 3px ${tint(p.token, 22)}` }} />
        {p.label}
      </span>
    );
  }
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6,
      padding: "2px 9px 2px 7px", borderRadius: 7, fontSize: 12, fontWeight: 600,
      color: tone(p.token), background: tint(p.token, 13),
      border: `1px solid ${tint(p.token, 28)}`, whiteSpace: "nowrap",
    }}>
      <span style={{ width: 6, height: 6, borderRadius: 2, background: tone(p.token), transform: "rotate(45deg)" }} />
      {p.label}
    </span>
  );
}

/* ---------- Avatar ---------- */
function Avatar({ id, size = 30, ring }) {
  const t = window.DB.techById(id) || { initials: "?", hue: 250, name: "" };
  return (
    <span title={t.name} style={{
      width: size, height: size, borderRadius: 99, flex: "0 0 auto",
      display: "inline-flex", alignItems: "center", justifyContent: "center",
      fontSize: size * 0.36, fontWeight: 600, letterSpacing: ".02em",
      color: `oklch(0.32 0.07 ${t.hue})`,
      background: `oklch(0.88 0.07 ${t.hue})`,
      border: ring ? "2px solid var(--surface)" : "none",
      boxShadow: ring ? "0 0 0 1px var(--border)" : "none",
    }}>{t.initials}</span>
  );
}
function AvatarStack({ ids, size = 28 }) {
  return (
    <span style={{ display: "inline-flex" }}>
      {ids.map((id, i) => (
        <span key={id} style={{ marginLeft: i ? -size * 0.32 : 0, zIndex: ids.length - i }}>
          <Avatar id={id} size={size} ring />
        </span>
      ))}
    </span>
  );
}
function AssigneeCell({ id }) {
  const t = window.DB.techById(id);
  if (!t) return <span style={{ color: "var(--text-faint)" }}>Unassigned</span>;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 9 }}>
      <Avatar id={id} size={26} />
      <span style={{ fontWeight: 500 }}>{t.name}</span>
    </span>
  );
}

/* ---------- Button ---------- */
function Button({ children, variant = "default", size = "md", icon, iconRight, onClick, style, title, active }) {
  const sizes = { sm: { h: 32, px: 11, fs: 13 }, md: { h: 38, px: 14, fs: 13.5 }, lg: { h: 44, px: 18, fs: 14.5 } };
  const z = sizes[size];
  const variants = {
    primary: { background: "var(--accent)", color: "var(--accent-fg)", border: "1px solid transparent", boxShadow: "var(--shadow-xs)" },
    default: { background: "var(--surface)", color: "var(--text)", border: "1px solid var(--border-strong)" },
    ghost:   { background: active ? "var(--surface-2)" : "transparent", color: "var(--text-muted)", border: "1px solid transparent" },
    soft:    { background: "var(--surface-2)", color: "var(--text)", border: "1px solid var(--border)" },
    danger:  { background: tint("--c-critical", 14), color: "var(--c-critical)", border: `1px solid ${tint("--c-critical", 30)}` },
  };
  const [h, setH] = useState(false);
  return (
    <button
      onClick={onClick} title={title}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8,
        height: z.h, padding: `0 ${z.px}px`, fontSize: z.fs, fontWeight: 600,
        fontFamily: "var(--font-sans)", borderRadius: "var(--radius-sm)", cursor: "pointer",
        whiteSpace: "nowrap", filter: h ? "brightness(0.97)" : "none",
        transform: h ? "translateY(-1px)" : "none", transition: "all .15s ease",
        ...variants[variant], ...style,
      }}
    >
      {icon && <Icon name={icon} size={z.fs + 3} />}
      {children}
      {iconRight && <Icon name={iconRight} size={z.fs + 2} />}
    </button>
  );
}
function IconButton({ icon, onClick, title, size = 38, active, badge }) {
  const [h, setH] = useState(false);
  return (
    <button onClick={onClick} title={title}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        position: "relative", width: size, height: size, borderRadius: "var(--radius-sm)",
        display: "inline-flex", alignItems: "center", justifyContent: "center", cursor: "pointer",
        background: active || h ? "var(--surface-2)" : "transparent",
        color: active ? "var(--accent-strong)" : "var(--text-muted)",
        border: "1px solid", borderColor: active ? "var(--border)" : "transparent", transition: "all .15s ease",
      }}>
      <Icon name={icon} size={19} />
      {badge ? <span style={{ position: "absolute", top: 7, right: 8, width: 7, height: 7, borderRadius: 99, background: "var(--c-critical)", border: "1.5px solid var(--surface)" }} /> : null}
    </button>
  );
}

/* ---------- Segmented control ---------- */
function Segmented({ options, value, onChange, counts }) {
  return (
    <div style={{ display: "inline-flex", background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: "var(--radius-sm)", padding: 3, gap: 2 }}>
      {options.map((o) => {
        const key = typeof o === "string" ? o : o.key;
        const label = typeof o === "string" ? o : o.label;
        const on = value === key;
        return (
          <button key={key} onClick={() => onChange(key)} style={{
            display: "inline-flex", alignItems: "center", gap: 7, padding: "6px 13px",
            fontSize: 13, fontWeight: 600, borderRadius: "calc(var(--radius-sm) - 2px)", cursor: "pointer",
            color: on ? "var(--text)" : "var(--text-muted)",
            background: on ? "var(--surface)" : "transparent",
            boxShadow: on ? "var(--shadow-xs)" : "none",
            border: on ? "1px solid var(--border)" : "1px solid transparent", transition: "all .15s ease",
          }}>
            {label}
            {counts && counts[key] != null && (
              <span className="tnum" style={{ fontSize: 11.5, fontWeight: 700, color: on ? "var(--accent-strong)" : "var(--text-faint)", background: on ? tint("--accent", 14) : "var(--surface-3)", borderRadius: 99, padding: "1px 6px", minWidth: 18, textAlign: "center" }}>{counts[key]}</span>
            )}
          </button>
        );
      })}
    </div>
  );
}

/* ---------- KPI card ---------- */
function KpiCard({ icon, label, value, suffix, delta, deltaGood, sub, token = "--accent", spark }) {
  const up = delta != null && delta >= 0;
  const good = deltaGood != null ? deltaGood : up;
  return (
    <Card className="kpi" hover style={{ display: "flex", flexDirection: "column", gap: 14, minWidth: 0 }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
        <span style={{ width: 38, height: 38, borderRadius: "var(--radius-sm)", display: "inline-flex", alignItems: "center", justifyContent: "center", background: tint(token, 16), color: tone(token) }}>
          <Icon name={icon} size={19} />
        </span>
        {delta != null && (
          <span style={{ display: "inline-flex", alignItems: "center", gap: 3, fontSize: 12.5, fontWeight: 700,
            color: good ? "var(--c-done)" : "var(--c-critical)",
            background: good ? tint("--c-done", 13) : tint("--c-critical", 13),
            padding: "3px 8px", borderRadius: 99 }}>
            <Icon name={up ? "arrowUp" : "arrowDown"} size={13} stroke={2.6} />
            {Math.abs(delta)}%
          </span>
        )}
      </div>
      <div>
        <div style={{ display: "flex", alignItems: "baseline", gap: 4 }}>
          <span className="tnum" style={{ fontSize: 30, fontWeight: 700, letterSpacing: "-.02em", lineHeight: 1 }}>{value}</span>
          {suffix && <span style={{ fontSize: 16, fontWeight: 600, color: "var(--text-muted)" }}>{suffix}</span>}
        </div>
        <div style={{ marginTop: 6, fontSize: 13, color: "var(--text-muted)", fontWeight: 500 }}>{label}</div>
        {sub && <div style={{ marginTop: 2, fontSize: 12, color: "var(--text-faint)" }}>{sub}</div>}
      </div>
      {spark && <Sparkline data={spark} token={token} />}
    </Card>
  );
}

/* ---------- Sparkline ---------- */
function Sparkline({ data, token = "--accent", h = 28 }) {
  const w = 120, max = Math.max(...data), min = Math.min(...data);
  const pts = data.map((d, i) => [ (i / (data.length - 1)) * w, h - ((d - min) / (max - min || 1)) * (h - 4) - 2 ]);
  const path = pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
  const area = path + ` L${w} ${h} L0 ${h} Z`;
  const gid = "sp" + Math.random().toString(36).slice(2, 7);
  return (
    <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ width: "100%", height: h, display: "block" }}>
      <defs><linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
        <stop offset="0" stopColor={tone(token)} stopOpacity="0.22" /><stop offset="1" stopColor={tone(token)} stopOpacity="0" />
      </linearGradient></defs>
      <path d={area} fill={`url(#${gid})`} />
      <path d={path} fill="none" stroke={tone(token)} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

/* ---------- Section header ---------- */
function SectionHead({ title, sub, action }) {
  return (
    <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 12, marginBottom: 14 }}>
      <div>
        <h3 style={{ margin: 0, fontSize: 15.5, fontWeight: 650, letterSpacing: "-.01em" }}>{title}</h3>
        {sub && <p style={{ margin: "3px 0 0", fontSize: 12.5, color: "var(--text-faint)" }}>{sub}</p>}
      </div>
      {action}
    </div>
  );
}

window.UI = { Card, StatusBadge, PriorityPill, Avatar, AvatarStack, AssigneeCell, Button, IconButton, Segmented, KpiCard, Sparkline, SectionHead, tone, tint };
