/* Sentinel — UI primitives. Forks the Ginja product kit and adds the
   contract-review vocabulary: RiskBadge, RedlineDiff, Confidence, Provenance. */

/* Shared settings context (driven by the Tweaks panel). */
const SentinelCtx = React.createContext({
  consoleLayout: "split", redline: "inline", aiPanel: "full", riskStyle: "badge", density: "default",
});

/* ── Button ──────────────────────────────────────────────────────────────*/
function Button({ variant = "primary", shape = "default", size = "md", leadingIcon, trailingIcon, children, style = {}, ...rest }) {
  const pad = size === "sm" ? "6px 11px" : size === "lg" ? "11px 20px" : "9px 16px";
  const fs = size === "sm" ? 13 : 14;
  const base = {
    display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7,
    fontFamily: "var(--font-body)", fontSize: fs, fontWeight: 600, lineHeight: 1,
    padding: pad, border: "1px solid transparent", cursor: "pointer",
    borderRadius: shape === "pill" ? "var(--radius-full)" : "var(--radius-md)",
    transition: "background var(--motion-fast) var(--ease-standard), border-color var(--motion-fast), color var(--motion-fast), transform var(--motion-fast)",
    whiteSpace: "nowrap",
  };
  const variants = {
    primary:     { background: "var(--ec-primary)", color: "#fff" },
    accent:      { background: "var(--ec-accent)", color: "#fff" },
    secondary:   { background: "var(--bg-surface)", color: "var(--content-strong)", borderColor: "var(--border-strong)" },
    ghost:       { background: "transparent", color: "var(--ec-primary)" },
    subtle:      { background: "var(--bg-sunken)", color: "var(--content-base)" },
    link:        { background: "transparent", color: "var(--ec-link)", textDecoration: "underline", textUnderlineOffset: 2, padding: "9px 4px" },
    destructive: { background: "var(--ec-destructive)", color: "#fff" },
  };
  const hov = {
    primary: ["var(--ec-primary-hover)", "var(--ec-primary)"], accent: ["var(--ec-accent-hover)", "var(--ec-accent)"],
    secondary: ["var(--bg-sunken)", "var(--bg-surface)"], ghost: ["var(--green-50)", "transparent"],
    subtle: ["var(--border-base)", "var(--bg-sunken)"], destructive: ["var(--ec-destructive-hover)", "var(--ec-destructive)"],
  };
  return (
    <button style={{ ...base, ...variants[variant], ...style }}
      onMouseEnter={(e) => { if (hov[variant]) e.currentTarget.style.background = hov[variant][0]; }}
      onMouseLeave={(e) => { if (hov[variant]) e.currentTarget.style.background = hov[variant][1]; }}
      onMouseDown={(e) => (e.currentTarget.style.transform = "translateY(0.5px)")}
      onMouseUp={(e) => (e.currentTarget.style.transform = "none")}
      {...rest}>
      {leadingIcon && <Icon name={leadingIcon} size={15} />}{children}{trailingIcon && <Icon name={trailingIcon} size={15} />}
    </button>
  );
}

/* ── StatusBadge ─────────────────────────────────────────────────────────*/
function StatusBadge({ tone = "neutral", leadingDot = true, children, style = {} }) {
  const map = {
    success:  ["var(--ec-status-success-bg)",  "var(--ec-status-success-fg)"],
    warning:  ["var(--ec-status-warning-bg)",  "var(--ec-status-warning-fg)"],
    info:     ["var(--ec-status-info-bg)",     "var(--ec-status-info-fg)"],
    progress: ["var(--ec-status-progress-bg)", "var(--ec-status-progress-fg)"],
    neutral:  ["var(--ec-status-neutral-bg)",  "var(--ec-status-neutral-fg)"],
    open:     ["var(--ec-status-open-bg)",     "var(--ec-status-open-fg)"],
    danger:   ["var(--status-danger-bg)",      "var(--status-danger)"],
  };
  const [bg, fg] = map[tone] || map.neutral;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "3px 10px",
      borderRadius: "var(--radius-full)", fontSize: 12, fontWeight: 500, background: bg, color: fg, whiteSpace: "nowrap", ...style }}>
      {leadingDot && <span style={{ width: 6, height: 6, borderRadius: "50%", background: "currentColor" }} />}{children}
    </span>
  );
}

/* ── RiskBadge — switchable visual language (badge | dots | bar) ──────────*/
function RiskBadge({ risk, style = "badge", size = "md", showRoute = false }) {
  const r = RISK[risk]; if (!r) return null;
  const fs = size === "sm" ? 11 : 12;
  if (style === "dots") {
    return (
      <span style={{ display: "inline-flex", alignItems: "center", gap: 7 }} title={r.label}>
        <span style={{ display: "inline-flex", gap: 2.5 }}>
          {[0, 1, 2, 3, 4].map((i) => (
            <span key={i} style={{ width: 6, height: 6, borderRadius: "50%",
              background: i <= r.sev ? `var(--status-${r.tone === "neutral" ? "info" : r.tone})` : "var(--border-strong)",
              opacity: i <= r.sev ? 1 : 0.5 }} />
          ))}
        </span>
        <span style={{ fontSize: fs, fontWeight: 600, color: "var(--content-base)" }}>{r.short}</span>
      </span>
    );
  }
  if (style === "bar") {
    const col = `var(--status-${r.tone === "neutral" ? "info" : r.tone})`;
    return (
      <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }} title={r.label}>
        <span style={{ width: 38, height: 5, borderRadius: 999, background: "var(--bg-sunken)", overflow: "hidden", display: "inline-block" }}>
          <span style={{ display: "block", height: "100%", width: ((r.sev + 1) / 5 * 100) + "%", background: col, borderRadius: 999 }} />
        </span>
        <span style={{ fontSize: fs, fontWeight: 600, color: "var(--content-strong)" }}>{r.short}</span>
      </span>
    );
  }
  // badge (default)
  const tone = r.tone;
  const colors = {
    minor:   ["var(--ec-status-neutral-bg)", "var(--ec-status-neutral-fg)"],
    low:     ["var(--ec-status-success-bg)", "var(--ec-status-success-fg)"],
    medlow:  ["var(--ec-status-info-bg)",    "var(--ec-status-info-fg)"],
    medhigh: ["var(--ec-status-warning-bg)", "var(--ec-status-warning-fg)"],
    high:    ["var(--status-danger-bg)",     "var(--status-danger)"],
  };
  const [bg, fg] = colors[risk];
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "3px 10px",
      borderRadius: "var(--radius-full)", fontSize: fs, fontWeight: 600, background: bg, color: fg, whiteSpace: "nowrap" }}>
      <span style={{ width: 6, height: 6, borderRadius: "50%", background: "currentColor" }} />{r.label}
    </span>
  );
}

/* ── Avatar ──────────────────────────────────────────────────────────────*/
function Avatar({ name = "", size = 36, tone = "green", style = {} }) {
  const initials = name.split(" ").map((w) => w[0]).slice(0, 2).join("").toUpperCase();
  const tones = {
    green: ["var(--green-100)", "var(--green-800)"], orange: ["var(--orange-100)", "var(--orange-800)"],
    teal: ["var(--teal-100)", "var(--teal-900)"], neutral: ["var(--neutral-200)", "var(--neutral-700)"],
  };
  const [bg, fg] = tones[tone] || tones.green;
  return (
    <span style={{ width: size, height: size, borderRadius: "var(--radius-full)", background: bg, color: fg,
      display: "inline-flex", alignItems: "center", justifyContent: "center", fontWeight: 600, fontSize: size * 0.38, flex: "none", ...style }}>{initials}</span>
  );
}

/* ── Card ────────────────────────────────────────────────────────────────*/
function Card({ children, style = {}, padding = 0, hover = false, ...rest }) {
  return (
    <div style={{ background: "var(--bg-surface)", border: "1px solid var(--border-base)",
      borderRadius: "var(--radius-lg)", boxShadow: "var(--elev-1)", padding,
      transition: hover ? "box-shadow var(--motion-base), border-color var(--motion-base)" : "none", ...style }}
      onMouseEnter={hover ? (e) => { e.currentTarget.style.boxShadow = "var(--elev-2)"; e.currentTarget.style.borderColor = "var(--border-strong)"; } : undefined}
      onMouseLeave={hover ? (e) => { e.currentTarget.style.boxShadow = "var(--elev-1)"; e.currentTarget.style.borderColor = "var(--border-base)"; } : undefined}
      {...rest}>{children}</div>
  );
}

/* ── KpiCard ─────────────────────────────────────────────────────────────*/
function KpiCard({ label, value, sub, subTone, icon, accent }) {
  return (
    <Card padding={16} style={{ flex: 1, minWidth: 0 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }}>
        {icon && <span style={{ color: accent || "var(--content-muted)" }}><Icon name={icon} size={16} /></span>}
        <span className="text-label">{label}</span>
      </div>
      <div className="gj-money" style={{ fontSize: 30, color: "var(--content-strong)", lineHeight: 1 }}>{value}</div>
      {sub && <div style={{ marginTop: 8, fontSize: 13, fontWeight: 500,
        color: subTone === "danger" ? "var(--status-danger)" : subTone === "warning" ? "var(--status-warning)" : subTone === "muted" ? "var(--content-muted)" : "var(--status-success)" }}>{sub}</div>}
    </Card>
  );
}

/* ── Eyebrow / micro-label ───────────────────────────────────────────────*/
function Label({ children, style = {} }) {
  return <span className="text-label" style={style}>{children}</span>;
}

/* ── Word-level redline diff engine (LCS) ────────────────────────────────*/
function diffWords(a, b) {
  const aw = a.split(/(\s+)/), bw = b.split(/(\s+)/);
  const n = aw.length, m = bw.length;
  const dp = Array.from({ length: n + 1 }, () => new Int32Array(m + 1));
  for (let i = n - 1; i >= 0; i--)
    for (let j = m - 1; j >= 0; j--)
      dp[i][j] = aw[i] === bw[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
  const out = []; let i = 0, j = 0;
  const push = (type, text) => { const last = out[out.length - 1]; if (last && last.type === type) last.text += text; else out.push({ type, text }); };
  while (i < n && j < m) {
    if (aw[i] === bw[j]) { push("same", aw[i]); i++; j++; }
    else if (dp[i + 1][j] >= dp[i][j + 1]) { push("del", aw[i]); i++; }
    else { push("ins", bw[j]); j++; }
  }
  while (i < n) { push("del", aw[i]); i++; }
  while (j < m) { push("ins", bw[j]); j++; }
  return out;
}

/* RedlineDiff — inline (tracked-changes look) or side-by-side. */
function RedlineDiff({ standard, provider, mode = "inline" }) {
  const segs = React.useMemo(() => diffWords(standard, provider), [standard, provider]);
  if (mode === "side") {
    return (
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
        <DiffColumn label="Our standard" tone="neutral" segs={segs} keep="del" />
        <DiffColumn label="Provider's version" tone="provider" segs={segs} keep="ins" />
      </div>
    );
  }
  return (
    <div style={{ background: "var(--bg-surface)", border: "1px solid var(--border-base)", borderRadius: "var(--radius-md)", padding: "13px 15px",
      fontSize: 13.5, lineHeight: 1.7, color: "var(--content-base)", fontFamily: "var(--font-body)" }}>
      {segs.map((s, k) => {
        if (s.type === "same") return <span key={k}>{s.text}</span>;
        if (s.type === "del") return <span key={k} style={{ textDecoration: "line-through", textDecorationColor: "var(--status-danger)", color: "var(--status-danger)", background: "var(--status-danger-bg)" }}>{s.text}</span>;
        return <span key={k} style={{ textDecoration: "underline", textDecorationColor: "var(--status-success)", color: "var(--status-success)", background: "var(--ec-status-success-bg)", fontWeight: 500 }}>{s.text}</span>;
      })}
    </div>
  );
}
function DiffColumn({ label, segs, keep, tone }) {
  return (
    <div style={{ background: tone === "provider" ? "var(--bg-page)" : "var(--bg-sunken)", border: "1px solid var(--border-base)", borderRadius: "var(--radius-md)", overflow: "hidden" }}>
      <div style={{ padding: "7px 12px", borderBottom: "1px solid var(--border-base)", display: "flex", alignItems: "center", gap: 6,
        background: tone === "provider" ? "var(--bg-surface)" : "transparent" }}>
        <Icon name={tone === "provider" ? "file-pen" : "file-check"} size={13} style={{ color: "var(--content-muted)" }} />
        <span className="text-label">{label}</span>
      </div>
      <div style={{ padding: "11px 13px", fontSize: 13, lineHeight: 1.65, color: "var(--content-base)" }}>
        {segs.filter((s) => s.type === "same" || s.type === keep).map((s, k) => {
          if (s.type === "same") return <span key={k}>{s.text}</span>;
          const ins = keep === "ins";
          return <span key={k} style={{ background: ins ? "var(--ec-status-success-bg)" : "var(--status-danger-bg)",
            color: ins ? "var(--status-success)" : "var(--status-danger)", fontWeight: 500,
            textDecoration: ins ? "none" : "line-through" }}>{s.text}</span>;
        })}
      </div>
    </div>
  );
}

/* ── Confidence meter ────────────────────────────────────────────────────*/
function Confidence({ value, compact = false }) {
  const tone = value >= 80 ? "var(--status-success)" : value >= 60 ? "var(--status-warning)" : "var(--status-danger)";
  if (compact) {
    return (
      <span style={{ display: "inline-flex", alignItems: "center", gap: 7 }}>
        <span style={{ width: 40, height: 5, borderRadius: 999, background: "var(--bg-sunken)", overflow: "hidden" }}>
          <span style={{ display: "block", height: "100%", width: value + "%", background: tone, borderRadius: 999 }} />
        </span>
        <span className="text-mono" style={{ color: tone, fontWeight: 600 }}>{value}%</span>
      </span>
    );
  }
  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 6 }}>
        <Label>AI confidence</Label>
        <span className="gj-money" style={{ fontSize: 22, color: tone }}>{value}%</span>
      </div>
      <div style={{ height: 7, borderRadius: 999, background: "var(--bg-sunken)", overflow: "hidden" }}>
        <div style={{ width: value + "%", height: "100%", background: tone, borderRadius: 999, transition: "width var(--motion-slow) var(--ease-standard)" }} />
      </div>
    </div>
  );
}

/* ── Provenance trail (rules → AI → precedent) ───────────────────────────*/
function Provenance({ checks }) {
  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      {checks.map((c, i) => (
        <div key={i} style={{ display: "flex", gap: 11, padding: "10px 0", borderTop: i ? "1px solid var(--border-subtle)" : "none" }}>
          <span style={{ flex: "none", marginTop: 1, color: c.ok ? "var(--status-success)" : "var(--status-warning)" }}>
            <Icon name={c.ok ? "check-circle-2" : "alert-triangle"} size={16} />
          </span>
          <div>
            <div style={{ fontSize: 13, fontWeight: 600, color: "var(--content-strong)", marginBottom: 2 }}>{c.label}</div>
            <div style={{ fontSize: 13, color: "var(--content-muted)", lineHeight: 1.5 }}>{c.detail}</div>
          </div>
        </div>
      ))}
    </div>
  );
}

/* ── Field + Input + Toggle ──────────────────────────────────────────────*/
function Field({ label, hint, children }) {
  return (
    <label style={{ display: "block" }}>
      <span style={{ display: "block", fontSize: 13, fontWeight: 600, color: "var(--content-strong)", marginBottom: 6 }}>{label}</span>
      {children}
      {hint && <span style={{ display: "block", fontSize: 13, color: "var(--content-muted)", marginTop: 5 }}>{hint}</span>}
    </label>
  );
}
function Input({ style = {}, ...rest }) {
  const [focus, setFocus] = React.useState(false);
  return (
    <input onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
      style={{ width: "100%", fontFamily: "var(--font-body)", fontSize: 14, padding: "9px 12px",
        border: `1px solid ${focus ? "var(--ec-primary)" : "var(--border-strong)"}`, borderRadius: "var(--radius-md)",
        background: "var(--bg-surface)", color: "var(--content-strong)", outline: focus ? "2px solid var(--ec-ring)" : "none", outlineOffset: 1, boxSizing: "border-box", ...style }}
      {...rest} />
  );
}
function Toggle({ on, onChange, size = 38 }) {
  return (
    <button onClick={() => onChange(!on)} style={{ width: size, height: size * 0.58, borderRadius: 999, border: "none", cursor: "pointer",
      background: on ? "var(--ec-primary)" : "var(--border-strong)", position: "relative", transition: "background var(--motion-base)", flex: "none", padding: 0 }}>
      <span style={{ position: "absolute", top: 2, left: on ? size - size * 0.58 + 2 - 2 : 2, width: size * 0.58 - 4, height: size * 0.58 - 4,
        borderRadius: "50%", background: "#fff", transition: "left var(--motion-base) var(--ease-standard)", boxShadow: "var(--elev-1)" }} />
    </button>
  );
}

/* ── SLA pill (live countdown) ───────────────────────────────────────────*/
function SlaPill({ uploadedMs, size = "md" }) {
  const [, tick] = React.useState(0);
  React.useEffect(() => { const t = setInterval(() => tick((x) => x + 1), 1000); return () => clearInterval(t); }, []);
  const rem = slaRemainingMin(uploadedMs);
  const tone = slaTone(rem);
  const tc = { success: "var(--status-success)", warning: "var(--status-warning)", danger: "var(--status-danger)" }[tone];
  const bg = { success: "var(--ec-status-success-bg)", warning: "var(--ec-status-warning-bg)", danger: "var(--status-danger-bg)" }[tone];
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: size === "sm" ? "2px 8px" : "4px 11px",
      borderRadius: "var(--radius-full)", background: bg, color: tc, fontFamily: "var(--font-mono)", fontSize: size === "sm" ? 12 : 13, fontWeight: 600, whiteSpace: "nowrap" }}>
      <Icon name={rem < 0 ? "alarm-clock-off" : "timer"} size={size === "sm" ? 12 : 14} />
      {rem < 0 ? "SLA +" + fmtDuration(rem).replace("+", "") + " over" : fmtDuration(rem) + " left"}
    </span>
  );
}

Object.assign(window, {
  SentinelCtx, Button, StatusBadge, RiskBadge, Avatar, Card, KpiCard, Label,
  diffWords, RedlineDiff, Confidence, Provenance, Field, Input, Toggle, SlaPill,
});
