/* global React, Icon, Avatar, Pill, Badge, Checkbox */
/* Data: mock data + Table, FeedItem, ListRow, MetricRow */

const { useState, useMemo } = React;

/* ---------- Mock data ---------- */
const MOCK = {
  audits: [
    { id: "AUD-0142", name: "Loop 14 — Northbeam media mix", client: "Northbeam", status: "active", phase: "Diagnose", lead: "Inés Vidal", office: "MIA", spend: 280000, days: 11, sent: "2 hours ago", tone: "info" },
    { id: "AUD-0141", name: "BrandLens — Avenue9 reposition", client: "Avenue9", status: "active", phase: "Simulate", lead: "Marco Ferraro", office: "NYC", spend: 145000, days: 6, sent: "yesterday", tone: "info" },
    { id: "AUD-0140", name: "HIVE deployment — Caja Andina", client: "Caja Andina", status: "blocked", phase: "Simulate", lead: "Daniela Reyes", office: "SCL", spend: 92000, days: 18, sent: "3 days ago", tone: "warn" },
    { id: "AUD-0139", name: "Catalyst — Soltera retention", client: "Soltera", status: "active", phase: "Prescribe", lead: "Inés Vidal", office: "MIA", spend: 412000, days: 22, sent: "1 week ago", tone: "info" },
    { id: "AUD-0138", name: "Milton.AI — Magnet ops index", client: "Magnet Global", status: "review", phase: "Prescribe", lead: "Tomás Otero", office: "MIA", spend: 60000, days: 4, sent: "this morning", tone: "warn" },
    { id: "AUD-0137", name: "BIGSights — Vela cohort study", client: "Vela", status: "shipped", phase: "Shipped", lead: "Marco Ferraro", office: "NYC", spend: 188000, days: 9, sent: "Apr 28", tone: "pos" },
    { id: "AUD-0136", name: "BrandLens — Quirón comms refresh", client: "Quirón", status: "shipped", phase: "Shipped", lead: "Daniela Reyes", office: "SCL", spend: 75000, days: 14, sent: "Apr 21", tone: "pos" },
    { id: "AUD-0135", name: "Catalyst — Borealis spend reset", client: "Borealis", status: "archived", phase: "Archived", lead: "Tomás Otero", office: "MIA", spend: 524000, days: 28, sent: "Apr 03", tone: "neutral" },
  ],

  inbox: [
    { id: 1, from: "Milton.AI", title: "Loop 14 finished diagnose phase", body: "Northbeam diagnostic complete — 4 high-confidence issues, 2 worth simulating.", time: "12m", icon: <Icon.Spark size={14}/>, tone: "grad", unread: true, tag: "milton" },
    { id: 2, from: "Marco Ferraro", title: "Avenue9 — pull rates updated", body: "Latest CPMs landed. Want me to rerun the simulator before the 3pm review?", time: "38m", unread: true, tag: "team" },
    { id: 3, from: "HIVE", title: "Agent C-04 escalated — needs review", body: "Caja Andina ingestion paused; schema drift on `customers.json` since Friday.", time: "1h", icon: <Icon.Hive size={14}/>, tone: "warn", unread: true, tag: "agent" },
    { id: 4, from: "Daniela Reyes", title: "Quirón handoff doc, v2", body: "Final read on the comms calendar. Ready for client review.", time: "2h", tag: "team" },
    { id: 5, from: "Catalyst", title: "Weekly office hours · MIA", body: "Inés, Tomás, and 3 others added to Friday 11:00.", time: "3h", icon: <Icon.Bolt size={14}/>, tone: "info", tag: "system" },
    { id: 6, from: "Magnet Global", title: "Network sync — Q2 targets", body: "Reading list and 2024 brief enclosed.", time: "yesterday", tag: "external" },
    { id: 7, from: "BrandLens", title: "Avenue9 sentiment shift detected", body: "Brand sentiment moved +3.4 in 7 days. Driven by earned coverage.", time: "yesterday", icon: <Icon.Lens size={14}/>, tone: "pos", tag: "agent" },
    { id: 8, from: "Tomás Otero", title: "Borealis archive — confirmed", body: "Closed out the Borealis engagement. All artifacts in /archive.", time: "Apr 28", tag: "team" },
  ],

  members: [
    { name: "Inés Vidal", role: "Strategy lead", office: "MIA", email: "ines@bnmrglvz.com" },
    { name: "Marco Ferraro", role: "Senior strategist", office: "NYC", email: "marco@bnmrglvz.com" },
    { name: "Daniela Reyes", role: "Strategist", office: "SCL", email: "daniela@bnmrglvz.com" },
    { name: "Tomás Otero", role: "Engineer · HIVE", office: "MIA", email: "tomas@bnmrglvz.com" },
  ],

  // 30-day series
  s30: [124, 132, 128, 145, 152, 161, 158, 173, 180, 168, 176, 195, 210, 198, 206, 218, 224, 213, 232, 248, 240, 255, 271, 268, 282, 295, 305, 312, 326, 340],
  s30b: [98, 102, 110, 105, 112, 121, 118, 132, 138, 130, 140, 148, 158, 156, 162, 170, 174, 168, 180, 192, 188, 200, 212, 210, 220, 228, 240, 246, 256, 268],
  s12m: ["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],
  bars12: [142, 168, 184, 156, 198, 220, 245, 278, 262, 308, 326, 384],
};

/* ---------- Table ---------- */
function Table({ columns, rows, selectable, onRowClick, sticky = true }) {
  const [sel, setSel] = useState(new Set());
  const [sort, setSort] = useState({ key: null, dir: "asc" });

  const sorted = useMemo(() => {
    if (!sort.key) return rows;
    const r = [...rows].sort((a, b) => {
      const av = a[sort.key], bv = b[sort.key];
      if (av == null) return 1;
      if (bv == null) return -1;
      if (typeof av === "number") return sort.dir === "asc" ? av - bv : bv - av;
      return sort.dir === "asc" ? String(av).localeCompare(String(bv)) : String(bv).localeCompare(String(av));
    });
    return r;
  }, [rows, sort]);

  const allChecked = sel.size === rows.length && rows.length > 0;
  const someChecked = sel.size > 0 && !allChecked;
  const toggleAll = () => {
    if (allChecked || someChecked) setSel(new Set());
    else setSel(new Set(rows.map(r => r.id)));
  };
  const toggleOne = (id) => {
    const next = new Set(sel);
    next.has(id) ? next.delete(id) : next.add(id);
    setSel(next);
  };
  const onSort = (key) => {
    setSort(s => s.key === key ? { key, dir: s.dir === "asc" ? "desc" : "asc" } : { key, dir: "asc" });
  };

  return (
    <div className="card" style={{ padding: 0, overflow: "hidden" }}>
      {selectable && sel.size > 0 && (
        <div className="row between" style={{
          padding: "10px 16px", borderBottom: "1px solid var(--line)",
          background: "var(--bg-2)",
        }}>
          <span style={{ fontSize: 13 }}>
            <strong style={{ fontWeight: 600 }}>{sel.size}</strong>
            <span className="muted"> selected</span>
          </span>
          <div className="row gap-6">
            <button style={btnGhost}>Assign…</button>
            <button style={btnGhost}>Export</button>
            <button style={btnGhost}>Archive</button>
            <button onClick={() => setSel(new Set())} style={{ ...btnGhost, color: "var(--ink-3)" }}>Clear</button>
          </div>
        </div>
      )}
      <div style={{ overflowX: "auto" }} className="scroll">
        <table style={{ width: "100%", borderCollapse: "collapse", fontFamily: "var(--sans)" }}>
          <thead>
            <tr style={{
              borderBottom: "1px solid var(--line-2)",
              position: sticky ? "sticky" : "static", top: 0, background: "var(--bg)", zIndex: 1,
            }}>
              {selectable && (
                <th style={thStyle}>
                  <Checkbox checked={allChecked} indeterminate={someChecked} onChange={toggleAll}/>
                </th>
              )}
              {columns.map((c) => (
                <th key={c.key} style={{ ...thStyle, textAlign: c.align || "left", width: c.width, cursor: c.sortable ? "pointer" : "default" }}
                  onClick={() => c.sortable && onSort(c.key)}>
                  <span className="row gap-6" style={{ justifyContent: c.align === "right" ? "flex-end" : "flex-start" }}>
                    {c.label}
                    {c.sortable && (
                      <span style={{ display: "inline-flex", color: sort.key === c.key ? "var(--ink)" : "var(--ink-3)" }}>
                        {sort.key === c.key ? (sort.dir === "asc" ? <Icon.ChevronUp size={11}/> : <Icon.ChevronDown size={11}/>) : <Icon.Sort size={11}/>}
                      </span>
                    )}
                  </span>
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {sorted.map((r, ri) => (
              <tr key={r.id || ri}
                onClick={() => onRowClick && onRowClick(r)}
                style={{
                  borderBottom: "1px solid var(--line)",
                  cursor: onRowClick ? "pointer" : "default",
                  background: sel.has(r.id) ? "var(--bg-2)" : "transparent",
                  transition: "background 150ms ease",
                }}
                onMouseEnter={(e) => { if (!sel.has(r.id)) e.currentTarget.style.background = "var(--bg-2)"; }}
                onMouseLeave={(e) => { if (!sel.has(r.id)) e.currentTarget.style.background = "transparent"; }}
              >
                {selectable && (
                  <td style={tdStyle} onClick={(e) => { e.stopPropagation(); toggleOne(r.id); }}>
                    <Checkbox checked={sel.has(r.id)} onChange={() => toggleOne(r.id)}/>
                  </td>
                )}
                {columns.map((c) => (
                  <td key={c.key} style={{ ...tdStyle, textAlign: c.align || "left" }}>
                    {c.render ? c.render(r) : r[c.key]}
                  </td>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

const thStyle = {
  padding: "10px var(--d-cell-px)",
  fontFamily: "var(--mono)", fontSize: 10, fontWeight: 700,
  letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--ink-3)",
  whiteSpace: "nowrap",
};
const tdStyle = {
  padding: "var(--d-cell-py) var(--d-cell-px)",
  fontSize: 13, color: "var(--ink)",
  verticalAlign: "middle",
  height: "var(--d-row-h)",
};
const btnGhost = {
  border: "1px solid var(--line)", background: "var(--bg)", color: "var(--ink)",
  fontFamily: "var(--sans)", fontSize: 12, fontWeight: 500,
  padding: "5px 10px", borderRadius: "var(--r-sharp)", cursor: "pointer",
};

/* ---------- Feed item ---------- */
function FeedItem({ item, onClick, active }) {
  return (
    <div onClick={onClick} style={{
      padding: "16px 20px", borderBottom: "1px solid var(--line)",
      cursor: onClick ? "pointer" : "default",
      background: active ? "var(--bg-2)" : "transparent",
      borderLeft: active ? "2px solid var(--grad-4)" : "2px solid transparent",
      transition: "background 150ms ease",
    }}
    onMouseEnter={(e) => { if (!active) e.currentTarget.style.background = "var(--bg-2)"; }}
    onMouseLeave={(e) => { if (!active) e.currentTarget.style.background = "transparent"; }}>
      <div className="row gap-12" style={{ alignItems: "flex-start" }}>
        {item.icon ? (
          <span style={{
            width: 28, height: 28, flexShrink: 0,
            background: item.tone === "grad" ? "var(--brand-grad)" : item.tone === "warn" ? "var(--warn-bg)" : item.tone === "pos" ? "var(--pos-bg)" : "var(--bg-2)",
            color: item.tone === "grad" ? "white" : item.tone === "warn" ? "var(--warn)" : item.tone === "pos" ? "var(--pos)" : "var(--ink)",
            borderRadius: 4, display: "inline-flex", alignItems: "center", justifyContent: "center",
          }}>{item.icon}</span>
        ) : (
          <Avatar name={item.from} size={28}/>
        )}
        <div className="col" style={{ flex: 1, minWidth: 0 }}>
          <div className="row between gap-8" style={{ alignItems: "baseline" }}>
            <span style={{ fontSize: 13, fontWeight: 600, color: "var(--ink)" }}>{item.from}</span>
            <span className="mono" style={{ fontSize: 10, color: "var(--ink-3)" }}>{item.time}</span>
          </div>
          <div style={{ fontSize: 14, fontWeight: 500, marginTop: 2, color: "var(--ink)" }}>{item.title}</div>
          {item.body && <div style={{ fontSize: 13, color: "var(--ink-2)", marginTop: 4, lineHeight: 1.5,
            display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden" }}>{item.body}</div>}
        </div>
        {item.unread && <i style={{ width: 6, height: 6, background: "var(--grad-4)", borderRadius: 999, flexShrink: 0, marginTop: 8 }}/>}
      </div>
    </div>
  );
}

/* ---------- Status pill (audit-specific colors) ---------- */
function StatusPill({ status }) {
  const map = {
    active: { tone: "info", label: "Active" },
    blocked: { tone: "warn", label: "Blocked" },
    review: { tone: "warn", label: "In review" },
    shipped: { tone: "pos", label: "Shipped" },
    archived: { tone: "neutral", label: "Archived" },
  };
  const m = map[status] || map.active;
  return <Pill tone={m.tone} dot>{m.label}</Pill>;
}

window.MOCK = MOCK;
Object.assign(window, { Table, FeedItem, StatusPill });
