// Clients / Engagements screen — sourced from Harvey_Client_List_5_4_26.xlsx (324 rows, $1.92M/mo).
// Replaces the old fake Projects mock. Shows all PEG-backed and independent engagements with
// monthly retainer, engagement type, PEG sponsor, module lead, and associates.

// Plain USD formatter — retainer values are absolute dollars (e.g. 6000 = $6,000/mo),
// not the "millions" units that fmtUSD assumes.
function fmtRetainer(n) {
  if (!n) return "$0";
  return "$" + Math.round(n).toLocaleString("en-US");
}

const _LEAD_TO_SUBTEAM = {
  // (intentionally empty — module → subteam mapping is now uniform: "st-" + leadId)
};
function subteamForLead(leadId) {
  if (!leadId || leadId === "multiple") return null;
  if (_LEAD_TO_SUBTEAM[leadId]) return _LEAD_TO_SUBTEAM[leadId];
  return "st-" + leadId;
}

function ProjectsScreen({ scope, setScope, period, setPeriod, year, setYear }) {
  const F = window.VAULT_FIRM;
  const { fmtUSD, fmtNum } = window.VaultUtils;
  const CLIENTS = window.HARVEY_CLIENTS || [];

  const [typeFilter, setTypeFilter] = useState("all"); // all | platform | addon | ceo
  const [catFilter, setCatFilter]   = useState("all"); // all | peg | indep | public
  const [view, setView]             = useState("clients"); // clients | sponsors
  const [search, setSearch]         = useState("");

  // Decorate each engagement with subteam + lead person.
  const enriched = useMemo(() => CLIENTS.map(c => {
    const subteamId = subteamForLead(c.lead);
    return {
      ...c,
      subteamId,
      leadPerson: F.PEOPLE_BY_ID[c.lead] || null,
      catKey: c.category === "PEG-Backed" ? "peg"
            : c.category === "Public company" ? "public"
            : "indep",
      typeKey: c.type === "Platform" ? "platform"
            : c.type === "Add-on" ? "addon"
            : c.type === "CEO" ? "ceo" : "other",
    };
  }), [CLIENTS]);

  const filtered = useMemo(() => {
    let xs = enriched;
    if (scope.subteam) xs = xs.filter(c => c.subteamId === scope.subteam);
    if (scope.individuals.length) {
      const ids = new Set(scope.individuals);
      xs = xs.filter(c => ids.has(c.lead) || (c.assoc || "").split("/").some(a => ids.has(a)));
    }
    if (typeFilter !== "all") xs = xs.filter(c => c.typeKey === typeFilter);
    if (catFilter  !== "all") xs = xs.filter(c => c.catKey === catFilter);
    if (search.trim()) {
      const q = search.trim().toLowerCase();
      xs = xs.filter(c =>
        c.client.toLowerCase().includes(q) ||
        c.peg.toLowerCase().includes(q) ||
        (c.lead || "").toLowerCase().includes(q));
    }
    return xs;
  }, [enriched, scope, typeFilter, catFilter, search]);

  // Headline stats over the filtered set.
  const stats = useMemo(() => {
    const retainer = filtered.reduce((s, c) => s + (c.retainer || 0), 0);
    const platforms = filtered.filter(c => c.typeKey === "platform").length;
    const addons    = filtered.filter(c => c.typeKey === "addon").length;
    const ceo       = filtered.filter(c => c.typeKey === "ceo").length;
    const sponsors  = new Set(filtered.filter(c => c.catKey === "peg").map(c => c.peg)).size;
    return { retainer, platforms, addons, ceo, sponsors, total: filtered.length };
  }, [filtered]);

  return (
    <div style={{ padding: "20px 28px 60px" }}>
      <div className="row" style={{ justifyContent: "space-between", flexWrap: "wrap", gap: 14, marginBottom: 18 }}>
        <window.ScopeFilters scope={scope} setScope={setScope}/>
        <div className="row" style={{ gap: 8 }}>
          <SearchBox value={search} onChange={setSearch}/>
        </div>
      </div>

      {/* Stat strip */}
      <div className="card" style={{ padding: 0, marginBottom: 16, display: "grid", gridTemplateColumns: "repeat(5, 1fr)", overflow: "hidden" }}>
        <StatCell label="Engagements" value={fmtNum(stats.total)} sub="active mandates"/>
        <StatCell label="Monthly retainer" value={fmtRetainer(stats.retainer)} sub="recurring fees" accent/>
        <StatCell label="Platforms" value={fmtNum(stats.platforms)} sub={stats.ceo ? `+ ${stats.ceo} CEO` : "sell-side"}/>
        <StatCell label="Add-ons" value={fmtNum(stats.addons)} sub="buy-side mandates"/>
        <StatCell label="PEG sponsors" value={fmtNum(stats.sponsors)} sub="unique funds" last/>
      </div>

      {/* Filters row */}
      <div className="row" style={{ marginBottom: 14, gap: 10, flexWrap: "wrap" }}>
        <div className="seg">
          {[
            { id: "clients",  label: "Engagements" },
            { id: "sponsors", label: "By Sponsor" },
          ].map(t => (
            <button key={t.id} className={view === t.id ? "on" : ""} onClick={() => setView(t.id)}>{t.label}</button>
          ))}
        </div>
        <div className="seg">
          {[
            { id: "all",      label: "All types" },
            { id: "platform", label: "Platform" },
            { id: "addon",    label: "Add-On" },
            { id: "ceo",      label: "CEO" },
          ].map(t => (
            <button key={t.id} className={typeFilter === t.id ? "on" : ""} onClick={() => setTypeFilter(t.id)}>{t.label}</button>
          ))}
        </div>
        <div className="seg">
          {[
            { id: "all",    label: "All" },
            { id: "peg",    label: "PEG-Backed" },
            { id: "indep",  label: "Independent" },
            { id: "public", label: "Public" },
          ].map(t => (
            <button key={t.id} className={catFilter === t.id ? "on" : ""} onClick={() => setCatFilter(t.id)}>{t.label}</button>
          ))}
        </div>
        <span className="muted small mono" style={{ marginLeft: "auto" }}>
          {filtered.length} of {enriched.length}
        </span>
      </div>

      {/* People filter strip — module leads + associates appearing in the visible set */}
      <PeopleFilterStrip rows={enriched} scope={scope} setScope={setScope}/>

      {view === "clients"  && <ClientsTable rows={filtered}/>}
      {view === "sponsors" && <SponsorList rows={filtered}/>}
    </div>
  );
}

// ---------- Sub-components ----------

function PeopleFilterStrip({ rows, scope, setScope }) {
  const F = window.VAULT_FIRM;
  // Tally leads + associates across all (pre-scope) engagements.
  const { leads, associates } = useMemo(() => {
    const leadMap = new Map(), assocMap = new Map();
    rows.forEach(c => {
      if (c.lead && c.lead !== "multiple") {
        leadMap.set(c.lead, (leadMap.get(c.lead) || 0) + 1);
      }
      (c.assoc || "").split("/").filter(Boolean).forEach(a => {
        assocMap.set(a, (assocMap.get(a) || 0) + 1);
      });
    });
    const toList = (m) => [...m.entries()]
      .map(([id, count]) => ({ id, count, person: F.PEOPLE_BY_ID[id] }))
      .filter(x => x.person)
      .sort((a, b) => b.count - a.count);
    return { leads: toList(leadMap), associates: toList(assocMap) };
  }, [rows]);

  const selected = new Set(scope.individuals);
  const toggle = (id) => {
    const next = selected.has(id)
      ? scope.individuals.filter(x => x !== id)
      : [...scope.individuals, id];
    setScope({ ...scope, individuals: next });
  };
  const clear = () => setScope({ ...scope, individuals: [] });

  if (leads.length === 0 && associates.length === 0) return null;

  return (
    <div className="card" style={{ padding: "10px 14px", marginBottom: 14, display: "flex", flexDirection: "column", gap: 8 }}>
      <PeopleRow label="Module leads" people={leads} selected={selected} toggle={toggle}/>
      {scope.individuals.length > 0 && (
        <div className="row" style={{ paddingTop: 4 }}>
          <span className="muted small">Filtering by {scope.individuals.length} {scope.individuals.length === 1 ? "person" : "people"}</span>
          <button className="btn ghost sm" onClick={clear} style={{ marginLeft: "auto", fontSize: 11 }}>Clear</button>
        </div>
      )}
    </div>
  );
}

function PeopleRow({ label, people, selected, toggle, dimmer }) {
  return (
    <div className="row" style={{ gap: 8, flexWrap: "wrap", alignItems: "center" }}>
      <div className="micro" style={{ fontSize: 10, width: 90, flexShrink: 0, color: "var(--muted)" }}>{label}</div>
      <div className="row" style={{ gap: 6, flexWrap: "wrap", flex: 1 }}>
        {people.map(({ id, count, person }) => {
          const on = selected.has(id);
          return (
            <button key={id} onClick={() => toggle(id)} title={`${person.name} · ${count} engagement${count === 1 ? "" : "s"}`}
              style={{
                display: "flex", alignItems: "center", gap: 5,
                padding: "3px 8px 3px 3px",
                border: "1px solid " + (on ? "var(--accent)" : "var(--line)"),
                background: on ? "var(--accent-soft)" : "var(--surface)",
                borderRadius: 999, cursor: "pointer",
                opacity: dimmer && !on ? 0.85 : 1,
                fontSize: 11.5, color: "var(--ink)",
                transition: "all .12s ease",
              }}>
              <window.Avatar id={id}/>
              <span style={{ fontWeight: 600 }}>{person.name.split(" ").pop()}</span>
              <span className="mono" style={{ fontSize: 10, color: on ? "var(--accent)" : "var(--muted)", marginLeft: 1 }}>
                {count}
              </span>
            </button>
          );
        })}
      </div>
    </div>
  );
}

function StatCell({ label, value, sub, accent, last }) {
  return (
    <div style={{
      padding: "14px 18px",
      borderRight: last ? "none" : "1px solid var(--line-2)",
      background: accent ? "linear-gradient(180deg, var(--accent-soft), transparent 70%)" : "transparent",
    }}>
      <div className="micro" style={{ fontSize: 10 }}>{label}</div>
      <div className="display" style={{
        fontSize: 24, lineHeight: 1.1, marginTop: 4, letterSpacing: "-.01em",
        color: accent ? "var(--accent)" : "var(--ink)",
      }}>{value}</div>
      <div className="muted small" style={{ marginTop: 2 }}>{sub}</div>
    </div>
  );
}

function SearchBox({ value, onChange }) {
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 6,
      border: "1px solid var(--line)", background: "var(--surface)",
      borderRadius: 8, padding: "5px 10px", minWidth: 240,
    }}>
      <svg width="13" height="13" viewBox="0 0 16 16" fill="none" style={{ color: "var(--muted)", flexShrink: 0 }}>
        <circle cx="7" cy="7" r="4.5" stroke="currentColor" strokeWidth="1.3"/>
        <path d="M10.5 10.5L14 14" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round"/>
      </svg>
      <input value={value} onChange={e => onChange(e.target.value)} placeholder="Search client, sponsor, lead…"
        style={{ flex: 1, border: "none", background: "transparent", outline: "none", fontSize: 12.5, color: "var(--ink)", minWidth: 0 }}/>
      {value && <button className="btn ghost sm" style={{ fontSize: 10 }} onClick={() => onChange("")}>×</button>}
    </div>
  );
}

function TypeBadge({ type }) {
  const map = {
    platform: { label: "Platform", tone: "info" },
    addon:    { label: "Add-On",   tone: "warn" },
    ceo:      { label: "CEO",      tone: "ok" },
  };
  const t = map[type] || { label: type, tone: "" };
  return <span className={`pill ${t.tone}`}><span className="dot"/>{t.label}</span>;
}

function ClientsTable({ rows }) {
  const F = window.VAULT_FIRM;
  const { fmtUSD } = window.VaultUtils;
  const [sortKey, setSortKey] = useState("retainer");
  const [sortDir, setSortDir] = useState("desc");

  const sorted = useMemo(() => {
    const xs = [...rows];
    const dir = sortDir === "asc" ? 1 : -1;
    xs.sort((a, b) => {
      let av = a[sortKey], bv = b[sortKey];
      if (sortKey === "client" || sortKey === "peg" || sortKey === "type")
        return (av || "").localeCompare(bv || "") * dir;
      if (sortKey === "pegNum") { av = av ?? 9999; bv = bv ?? 9999; }
      return ((av || 0) - (bv || 0)) * dir;
    });
    return xs;
  }, [rows, sortKey, sortDir]);

  const setSort = (k) => {
    if (sortKey === k) setSortDir(d => d === "asc" ? "desc" : "asc");
    else { setSortKey(k); setSortDir(k === "client" || k === "peg" ? "asc" : "desc"); }
  };

  const HeaderCell = ({ k, label, align = "left", w }) => (
    <th onClick={() => setSort(k)} style={{
      textAlign: align, padding: "10px 12px", cursor: "pointer", userSelect: "none",
      fontSize: 10.5, letterSpacing: ".05em", textTransform: "uppercase", color: "var(--muted)",
      fontWeight: 600, width: w, whiteSpace: "nowrap",
    }}>
      {label}
      {sortKey === k && <span style={{ marginLeft: 4, fontSize: 9, color: "var(--accent)" }}>{sortDir === "asc" ? "▲" : "▼"}</span>}
    </th>
  );

  return (
    <div className="card" style={{ padding: 0, overflow: "hidden" }}>
      <div style={{ maxHeight: "calc(100vh - 320px)", overflowY: "auto", overflowX: "auto" }}>
        <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12.5 }}>
          <thead style={{ position: "sticky", top: 0, background: "var(--surface)", zIndex: 1, borderBottom: "1px solid var(--line)" }}>
            <tr>
              <HeaderCell k="pegNum" label="#" w={50} align="right"/>
              <HeaderCell k="client" label="Client"/>
              <HeaderCell k="peg" label="PEG / Sponsor"/>
              <HeaderCell k="type" label="Type" w={110}/>
              <HeaderCell k="retainer" label="Retainer / mo" align="right" w={130}/>
              <th style={{ textAlign: "left", padding: "10px 12px", fontSize: 10.5, letterSpacing: ".05em", textTransform: "uppercase", color: "var(--muted)", fontWeight: 600 }}>Team</th>
            </tr>
          </thead>
          <tbody>
            {sorted.map((c, i) => (
              <tr key={c.id} style={{ borderBottom: "1px solid var(--line-2)", background: i % 2 ? "var(--surface-2)" : "transparent" }}>
                <td className="mono muted" style={{ padding: "9px 12px", textAlign: "right", fontSize: 11 }}>
                  {c.pegNum ?? "—"}
                </td>
                <td style={{ padding: "9px 12px" }}>
                  <div style={{ fontWeight: 600, color: "var(--ink)" }}>{c.client}</div>
                  {c.notes && <div className="muted" style={{ fontSize: 10.5, marginTop: 1 }}>{c.notes}</div>}
                </td>
                <td style={{ padding: "9px 12px" }}>
                  {c.catKey === "peg" ? (
                    <span style={{ color: "var(--ink-2)" }}>{c.peg}</span>
                  ) : c.catKey === "public" ? (
                    <span className="muted small">Public · {c.peg}</span>
                  ) : (
                    <span className="muted small">Independent · {c.peg}</span>
                  )}
                </td>
                <td style={{ padding: "9px 12px" }}><TypeBadge type={c.typeKey}/></td>
                <td className="mono" style={{ padding: "9px 12px", textAlign: "right", fontWeight: 600, color: c.retainer >= 10000 ? "var(--accent)" : "var(--ink)" }}>
                  {fmtRetainer(c.retainer)}
                </td>
                <td style={{ padding: "9px 12px" }}>
                  <TeamCell lead={c.lead} assoc={c.assoc}/>
                </td>
              </tr>
            ))}
            {sorted.length === 0 && (
              <tr><td colSpan={6} style={{ padding: "40px 12px", textAlign: "center" }} className="muted">
                No engagements match the current filters.
              </td></tr>
            )}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function TeamCell({ lead, assoc }) {
  const F = window.VAULT_FIRM;
  const leadPerson = F.PEOPLE_BY_ID[lead];
  const isMultiple = lead === "multiple";
  const associates = (assoc || "").split("/").filter(Boolean);

  return (
    <div className="row" style={{ gap: 6, flexWrap: "nowrap" }}>
      {isMultiple ? (
        <span style={{
          padding: "2px 8px", fontSize: 10.5, borderRadius: 999,
          background: "var(--surface-2)", border: "1px dashed var(--line)",
          color: "var(--muted)", fontWeight: 600, letterSpacing: ".03em", textTransform: "uppercase",
        }}>Multi-lead</span>
      ) : leadPerson ? (
        <div className="row" style={{ gap: 5, flexShrink: 0 }}>
          <window.Avatar id={leadPerson.id}/>
          <span style={{ fontSize: 11.5, fontWeight: 600 }}>{leadPerson.name.split(" ").pop()}</span>
        </div>
      ) : (
        <span className="muted small mono">{lead}</span>
      )}
      {associates.length > 0 && (
        <div className="row" style={{ gap: -4, marginLeft: 2 }}>
          {associates.slice(0, 3).map((a, i) => {
            const p = F.PEOPLE_BY_ID[a];
            return (
              <div key={a + i} title={p ? p.name : a} style={{ marginLeft: i === 0 ? 0 : -6, zIndex: associates.length - i }}>
                {p ? <window.Avatar id={p.id}/> : (
                  <span style={{
                    width: 22, height: 22, borderRadius: "50%",
                    background: "var(--surface-2)", border: "2px solid var(--surface)",
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    fontSize: 9, fontWeight: 700, color: "var(--muted)",
                  }}>{a.slice(0, 2).toUpperCase()}</span>
                )}
              </div>
            );
          })}
          {associates.length > 3 && (
            <span className="muted small" style={{ marginLeft: 4, fontSize: 10.5 }}>+{associates.length - 3}</span>
          )}
        </div>
      )}
    </div>
  );
}

function SponsorList({ rows }) {
  const { fmtUSD, fmtNum } = window.VaultUtils;
  // Group PEG-backed by sponsor; bucket independents/publics under their own headings.
  const groups = useMemo(() => {
    const map = new Map();
    rows.forEach(c => {
      const key = c.catKey === "peg" ? c.peg
                : c.catKey === "public" ? "__public__"
                : "__indep__";
      if (!map.has(key)) map.set(key, {
        key, label: c.catKey === "peg" ? c.peg : c.catKey === "public" ? "Public Companies" : "Independent Private Companies",
        sortNum: c.catKey === "peg" ? (c.pegNum ?? 9999) : (c.catKey === "public" ? 100001 : 100002),
        clients: [], retainer: 0,
      });
      const g = map.get(key);
      g.clients.push(c);
      g.retainer += c.retainer || 0;
    });
    return [...map.values()].sort((a, b) => a.sortNum - b.sortNum);
  }, [rows]);

  return (
    <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(380px, 1fr))", gap: 14 }}>
      {groups.map(g => (
        <div key={g.key} className="card" style={{ padding: 14, display: "flex", flexDirection: "column", gap: 8 }}>
          <div className="row" style={{ alignItems: "flex-start" }}>
            <div className="stretch" style={{ minWidth: 0 }}>
              {g.key !== "__public__" && g.key !== "__indep__" && (
                <div className="micro" style={{ fontSize: 10 }}>PEG · #{g.clients[0]?.pegNum ?? "—"}</div>
              )}
              <div className="display" style={{ fontSize: 17, lineHeight: 1.2, letterSpacing: "-.005em", marginTop: 2 }}>
                {g.label}
              </div>
              <div className="muted small" style={{ marginTop: 2 }}>
                {fmtNum(g.clients.length)} engagement{g.clients.length === 1 ? "" : "s"}
              </div>
            </div>
            <div style={{ textAlign: "right" }}>
              <div className="micro" style={{ fontSize: 9.5 }}>Retainer / mo</div>
              <div className="mono" style={{ fontWeight: 700, color: "var(--accent)", fontSize: 14 }}>{fmtRetainer(g.retainer)}</div>
            </div>
          </div>
          <div style={{ height: 1, background: "var(--line-2)" }}/>
          <div style={{ display: "flex", flexDirection: "column", gap: 5, maxHeight: 220, overflowY: "auto" }}>
            {g.clients.map(c => (
              <div key={c.id} className="row" style={{ gap: 8, padding: "4px 0" }}>
                <span style={{ flex: 1, fontSize: 12.5, color: "var(--ink)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {c.client}
                </span>
                <TypeBadge type={c.typeKey}/>
                <span className="mono small" style={{ minWidth: 60, textAlign: "right", color: "var(--ink-2)" }}>
                  {fmtRetainer(c.retainer)}
                </span>
              </div>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

window.ProjectsScreen = ProjectsScreen;
