/* global React */
const { useState, useEffect, useRef, createContext, useContext } = React;

/* ============================================================
   ICONS — clean 24px stroke set (Lucide-style)
   ============================================================ */
const ICONS = {
  command:   "M9 6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3z",
  grid:      "M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z",
  layers:    "M12 3l9 5-9 5-9-5 9-5zM3 14l9 5 9-5",
  database:  "M12 3c4.97 0 9 1.34 9 3s-4.03 3-9 3-9-1.34-9-3 4.03-3 9-3zM3 6v6c0 1.66 4.03 3 9 3s9-1.34 9-3V6M3 12v6c0 1.66 4.03 3 9 3s9-1.34 9-3v-6",
  shield:    "M12 3l8 3v6c0 4.5-3.2 7.7-8 9-4.8-1.3-8-4.5-8-9V6l8-3z",
  scale:     "M12 3v18M7 21h10M5 7h14M5 7l-2.5 6h5L5 7zM19 7l-2.5 6h5L19 7z",
  droplet:   "M12 3s6 5.5 6 10a6 6 0 0 1-12 0c0-4.5 6-10 6-10z",
  trending:  "M3 17l6-6 4 4 8-8M21 7v5M21 7h-5",
  activity:  "M22 12h-4l-3 9L9 3l-3 9H2",
  flask:     "M9 3h6M10 3v6l-5 9a2 2 0 0 0 1.8 3h10.4A2 2 0 0 0 19 18l-5-9V3M7.5 14h9",
  fileText:  "M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9l-6-6zM14 3v6h6M9 13h6M9 17h6",
  clipboard: "M9 3h6a1 1 0 0 1 1 1v1h2a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2V4a1 1 0 0 1 1-1zM9 5v1h6V5",
  settings:  "M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-2.81 1.17V22a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 8 20.4l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4 12.6V12.5a2 2 0 1 1 0-1.09 1.65 1.65 0 0 0 1.6-1.18l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 12 3.6V3.5a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1.82.33",
  users:     "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM22 21v-2a4 4 0 0 0-3-3.87M16 3.13A4 4 0 0 1 16 11",
  search:    "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM21 21l-4.3-4.3",
  bell:      "M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 0 1-3.4 0",
  help:      "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM9.1 9a3 3 0 0 1 5.8 1c0 2-3 3-3 3M12 17h.01",
  info:      "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 16v-4M12 8h.01",
  x:         "M18 6 6 18M6 6l12 12",
  chevR:     "M9 18l6-6-6-6",
  chevD:     "M6 9l6 6 6-6",
  chevUp:    "M18 15l-6-6-6 6",
  arrowR:    "M5 12h14M13 6l6 6-6 6",
  arrowUR:   "M7 17 17 7M7 7h10v10",
  check:     "M20 6 9 17l-5-5",
  checkCirc: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM8.5 12l2.5 2.5L16 9",
  alert:     "M12 9v4M12 17h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z",
  alertCirc: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 8v4M12 16h.01",
  clock:     "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 7v5l3 2",
  lock:      "M5 11h14v10H5zM8 11V7a4 4 0 0 1 8 0v4",
  upload:    "M12 15V3M7 8l5-5 5 5M5 17v2a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-2",
  download:  "M12 3v12M7 10l5 5 5-5M5 21h14",
  plug:      "M9 2v6M15 2v6M6 8h12v3a6 6 0 0 1-12 0V8zM12 17v5",
  gitBranch: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM18 9a9 9 0 0 1-9 9",
  link:      "M10 13a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1.5 1.5M14 11a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1.5-1.5",
  flag:      "M4 21V4h12l-1.5 4L16 12H4",
  filter:    "M3 4h18l-7 8v6l-4 2v-8L3 4z",
  calendar:  "M3 5h18v16H3zM3 9h18M8 3v4M16 3v4",
  building:  "M3 21h18M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16M9 7h.01M15 7h.01M9 11h.01M15 11h.01M9 15h6v6H9z",
  globe:     "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM3 12h18M12 3c2.5 2.5 3.5 6 3.5 9s-1 6.5-3.5 9c-2.5-2.5-3.5-6-3.5-9s1-6.5 3.5-9z",
  zap:       "M13 2 4 14h7l-1 8 9-12h-7l1-8z",
  hash:      "M4 9h16M4 15h16M10 3 8 21M16 3l-2 18",
  eye:       "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7zM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z",
  sliders:   "M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3M1 14h6M9 8h6M17 16h6",
  refresh:   "M21 12a9 9 0 1 1-3-6.7L21 8M21 3v5h-5",
  panelLeft: "M3 4h18v16H3zM9 4v16",
  panelRight:"M3 4h18v16H3zM15 4v16",
  dollar:    "M12 1v22M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6",
  more:      "M12 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM12 6a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM12 20a1 1 0 1 0 0-2 1 1 0 0 0 0 2z",
  map:       "M9 4 3 6v14l6-2 6 2 6-2V4l-6 2-6-2zM9 4v14M15 6v14",
  inbox:     "M4 13h4l1 3h6l1-3h4M4 13 6 5h12l2 8v6H4v-6z",
  briefcase: "M3 8h18v12H3zM8 8V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v3",
  pieChart:  "M21 15.5A9 9 0 1 1 8.5 3M21 12a9 9 0 0 0-9-9v9h9z",
  list:      "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01",
};

function Icon({ name, size = 18, className = "", style = {}, fill = false }) {
  const d = ICONS[name] || ICONS.grid;
  return (
    <svg className={"ic " + className} width={size} height={size} viewBox="0 0 24 24"
      fill={fill ? "currentColor" : "none"} stroke="currentColor" strokeWidth="1.7"
      strokeLinecap="round" strokeLinejoin="round" style={style} aria-hidden="true">
      {d.split("M").filter(Boolean).map((seg, i) => <path key={i} d={"M" + seg} />)}
    </svg>
  );
}

/* ============================================================
   STATUS CHIP — readiness taxonomy → bank-friendly copy
   ============================================================ */
const STATUS = {
  APPROVED_INTERNAL: { label: "Approved · internal", cls: "chip-green", dot: true, help: "Reviewed and approved as an internal workpaper. Not an official NBE submission." },
  RECONCILED:        { label: "Reconciled", cls: "chip-green", dot: true, help: "Source ties to workpaper. Rule evidence and approval may still be pending." },
  MAPPED:            { label: "Mapped", cls: "chip-slate", dot: true, help: "Source fields mapped to target. Not yet reconciled." },
  REVIEW_PENDING:    { label: "Review pending", cls: "chip-amber", dot: true, help: "Awaiting checker review before it can advance." },
  EVIDENCE_NEEDED:   { label: "Rule evidence needed", cls: "chip-amber", dot: true, help: "An NBE rule reference must be attached and reviewed before official use." },
  NEEDS_BANK_POLICY: { label: "Bank policy needed", cls: "chip-amber", dot: true, help: "A bank policy value (assumption/limit) must be configured." },
  VALIDATION_FAILED: { label: "Validation failed", cls: "chip-red", dot: true, help: "Rows failed schema validation. Triage required before mapping." },
  SOURCE_MISSING:    { label: "Source missing", cls: "chip-red", dot: true, help: "A required source snapshot has not been provided for this cycle." },
  EXPORT_BLOCKED:    { label: "Official export blocked", cls: "chip-red", dot: true, help: "Source, rule, lineage, validation, and approvals are incomplete." },
  STRESS_ONLY:       { label: "Stress · analysis-only", cls: "chip-indigo", dot: true, help: "Scenario output. Never merged into official baseline values." },
  IMPACT_NC:         { label: "Impact not computed", cls: "chip-slate", dot: true, help: "Source/rule/method evidence is missing, so no official impact is shown." },
  CONFIG_REQUIRED:   { label: "Configuration required", cls: "chip-neutral", dot: true, help: "This module needs a data contract / template configured before use." },
  SYNTHETIC:         { label: "Synthetic test source", cls: "chip-indigo", dot: false, help: "Used to test workflow only. Not bank-confirmed production data." },
  INTERNAL_WP:       { label: "Internal workpaper", cls: "chip-slate", dot: true, help: "Analysis workspace. Not an official calculation or submission." },
  OFFICIAL_FUTURE:   { label: "Official · future", cls: "chip-neutral", dot: false, help: "Official export is planned but not yet available." },
  NEEDS_RULE_EVIDENCE:       { label: "Needs rule evidence", cls: "chip-red", dot: true, help: "No NBE rule reference attached. Blocks official export." },
  EVIDENCE_ATTACHED:         { label: "Evidence attached", cls: "chip-amber", dot: true, help: "Evidence attached but not yet checked. Attached ≠ verified." },
  RETURNED_FOR_CLARIFICATION:{ label: "Returned for clarification", cls: "chip-red", dot: true, help: "Checker returned the evidence; the maker must clarify." },
  BANK_CONFIRMED:            { label: "Bank-confirmed", cls: "chip-green", dot: true, help: "Confirmed against board-approved bank policy. Export-eligible." },
  OFFICIAL_VERIFIED:         { label: "Official-verified", cls: "chip-green", dot: true, help: "Attached and checked against an NBE directive. Export-eligible." },
  TEMPLATE_INFERRED:         { label: "Template-inferred", cls: "chip-amber", dot: true, help: "Carried from a template, not verified. Template-inferred ≠ official." },
  EXPIRED:                   { label: "Rule expired", cls: "chip-red", dot: true, help: "Superseded by a newer directive. Re-verify impacted metrics." },
  CONFLICTING_EVIDENCE:      { label: "Conflicting evidence", cls: "chip-red", dot: true, help: "Two references disagree on this treatment. Resolve before official use." },
};

function StatusChip({ s, lg, onClick }) {
  const cfg = STATUS[s] || { label: s, cls: "chip-neutral", dot: true, help: "" };
  return (
    <span className={"chip " + cfg.cls + (lg ? " chip-lg" : "")} title={cfg.help}
      onClick={onClick} style={onClick ? { cursor: "pointer" } : null}>
      {cfg.dot && <span className="dot" />}{cfg.label}
    </span>
  );
}

/* ============================================================
   AVATAR
   ============================================================ */
const AV_COLORS = ["#4F4DD0","#138A47","#B5750C","#C23A28","#5A6472","#7A3FB0","#0E7C86","#B0457A"];
function Avatar({ name, size = 26 }) {
  const initials = (name || "?").split(" ").map(w => w[0]).slice(0, 2).join("").toUpperCase();
  const c = AV_COLORS[(name || "").length % AV_COLORS.length];
  return <span className="av" style={{ width: size, height: size, background: c, fontSize: size * .4 }}>{initials}</span>;
}

/* ============================================================
   DRAWER shell
   ============================================================ */
function Drawer({ open, onClose, children, wide }) {
  useEffect(() => {
    const h = e => { if (e.key === "Escape") onClose(); };
    if (open) window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <React.Fragment>
      <div className="scrim" onClick={onClose} />
      <aside className={"drawer" + (wide ? " wide" : "")} role="dialog">{children}</aside>
    </React.Fragment>
  );
}

function DrawerHead({ title, sub, chip, onClose }) {
  return (
    <div className="drawer-h">
      <div>
        <div style={{ fontSize: 17, fontWeight: 800, letterSpacing: "-.02em" }}>{title}</div>
        {sub && <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>{sub}</div>}
        {chip && <div style={{ marginTop: 9 }}>{chip}</div>}
      </div>
      <button className="icon-btn x" onClick={onClose} aria-label="Close"><Icon name="x" size={16} /></button>
    </div>
  );
}

/* simple tabs */
function Tabs({ tabs, active, onChange }) {
  return (
    <div className="tabs">
      {tabs.map(t => (
        <div key={t} className={"tab" + (active === t ? " active" : "")} onClick={() => onChange(t)}>{t}</div>
      ))}
    </div>
  );
}

/* meta list */
function Meta({ rows }) {
  return (
    <dl className="meta">
      {rows.map(([k, v], i) => <React.Fragment key={i}><dt>{k}</dt><dd>{v}</dd></React.Fragment>)}
    </dl>
  );
}

/* banner */
function Banner({ kind = "amber", icon = "alert", children }) {
  return (
    <div className={"banner banner-" + kind}>
      <Icon name={icon} size={18} className="ic" />
      <div>{children}</div>
    </div>
  );
}

/* toast hook */
function useToast() {
  const [msg, setMsg] = useState(null);
  const show = (m) => { setMsg(m); setTimeout(() => setMsg(null), 2400); };
  const node = msg ? <div className="toast"><Icon name="check" /> {msg}</div> : null;
  return [node, show];
}

function ActionDrawer({ action, onClose }) {
  if (!action) return null;
  const rows = action.rows || [];
  const items = action.items || [];
  return (
    <Drawer open={!!action} onClose={onClose} wide={action.wide}>
      <DrawerHead
        title={action.title || "Internal workflow action"}
        sub={action.sub || "Internal workflow only"}
        chip={action.chip}
        onClose={onClose}
      />
      <div className="drawer-body">
        <Banner kind={action.kind || "indigo"} icon={action.icon || "info"}>
          {action.banner || <span><b>Internal workflow action recorded.</b> This updates the review workflow only. No backend engine, export writer, live connector, approval execution, or regulator submission is run.</span>}
        </Banner>
        {action.body && <div className="mt16" style={{ fontSize: 13.5, color: "var(--ink-2)", lineHeight: 1.5 }}>{action.body}</div>}
        {rows.length > 0 && <div className="mt16"><Meta rows={rows} /></div>}
        {items.length > 0 && <div className="mt16">
          <div className="section-label mb8">{action.itemsTitle || "Next checks"}</div>
          {items.map((item, i) => (
            <div key={i} className="cl">
              <span className="cl-ic" style={{ background: "var(--surface-2)", color: "var(--ink-2)" }}><Icon name={item.icon || "check"} size={15} /></span>
              <div className="grow">
                <div style={{ fontWeight: 600, fontSize: 13 }}>{item.title || item}</div>
                {item.body && <div className="muted" style={{ fontSize: 12 }}>{item.body}</div>}
              </div>
            </div>
          ))}
        </div>}
        <div className="mt16">
          <Banner kind="amber" icon="lock">
            <b>Guardrail.</b> {action.guardrail || "This remains controlled internal review state. Official export stays blocked until all gates pass in Export Gate."}
          </Banner>
        </div>
      </div>
      <div className="drawer-foot">
        {action.secondary && <button className="btn btn-ghost" onClick={action.onSecondary || onClose}>{action.secondary}</button>}
        <button className="btn btn-dark" style={{ marginLeft: "auto" }} onClick={action.onPrimary || onClose}>{action.primary || "Done"}</button>
      </div>
    </Drawer>
  );
}

function useActionDrawer() {
  const [action, setAction] = useState(null);
  const close = () => setAction(null);
  const open = (cfg) => setAction(typeof cfg === "string" ? { title: cfg } : cfg);
  return [<ActionDrawer action={action} onClose={close} />, open, close];
}

Object.assign(window, { Icon, ICONS, StatusChip, STATUS, Avatar, Drawer, DrawerHead, Tabs, Meta, Banner, useToast, ActionDrawer, useActionDrawer, StateView });

/* ============================================================
   STATE VIEW — reusable empty / loading / error / blocked panel
   ============================================================ */
function StateView({ kind, title, body, icon, action, onAction }) {
  if (kind === "loading") {
    return (
      <div className="card" style={{ padding: "48px 24px", textAlign: "center" }}>
        <div className="sv-spin" style={{ margin: "0 auto 16px" }} />
        <div style={{ fontWeight: 700, fontSize: 15 }}>{title || "Loading…"}</div>
        {body && <div className="muted" style={{ fontSize: 13, marginTop: 4 }}>{body}</div>}
      </div>
    );
  }
  const cfg = {
    empty:   { ic: icon || "inbox",     bg: "var(--surface-2)", c: "var(--ink-3)" },
    error:   { ic: icon || "alertCirc", bg: "var(--red-soft)",  c: "var(--red)" },
    blocked: { ic: icon || "lock",      bg: "var(--amber-soft)",c: "var(--amber)" },
  }[kind] || { ic: "info", bg: "var(--surface-2)", c: "var(--ink-3)" };
  return (
    <div className="card" style={{ padding: "44px 24px", textAlign: "center" }}>
      <div style={{ width: 56, height: 56, borderRadius: 14, background: cfg.bg, color: cfg.c, display: "grid", placeItems: "center", margin: "0 auto 16px" }}><Icon name={cfg.ic} size={26} /></div>
      <div style={{ fontWeight: 800, fontSize: 17, letterSpacing: "-.01em" }}>{title}</div>
      {body && <div className="muted" style={{ fontSize: 13.5, marginTop: 6, maxWidth: 460, marginLeft: "auto", marginRight: "auto", lineHeight: 1.5 }}>{body}</div>}
      {action && <button className={"btn btn-sm " + (kind === "error" || kind === "blocked" ? "btn-ghost" : "btn-primary")} style={{ marginTop: 18 }} onClick={onAction}>{action}</button>}
    </div>
  );
}
