/* =========================================================================
   Live ICP Tracker — Ranked Target List / Dashboard (internal)
   Layouts: table | cards | tiers. Enrichment: minimal | standard | rich.
   Exports: ListView
   ========================================================================= */
  const { useState, useMemo, useRef, useEffect, useCallback } = React;

/* ---------- SAVED LISTS store (Supabase-backed, team-wide) --------------
   Persisted in Supabase via /api/saved-lists. Lists store account IDs on the
   server; locally we resolve those IDs to full account objects from
   window.ICP.ACCOUNTS so the rest of the UI keeps working unchanged.
   Mutations are optimistic and then reconciled with the server response. */
const SavedListsStore = (function () {
  let lists = [];          // [{ id, name, createdAt, accountIds:[], accounts:[resolved] }]
  let loaded = false;
  let loading = false;
  const subs = new Set();
  const emit = () => subs.forEach(fn => fn());

  function accountMap() {
    const m = new Map();
    (window.ICP?.ACCOUNTS || []).forEach(a => m.set(a.id, a));
    return m;
  }
  function resolve(ids) {
    const m = accountMap();
    return ids.map(id => m.get(id)).filter(Boolean);
  }
  function hydrate(raw) {
    return { id: raw.id, name: raw.name, createdAt: raw.createdAt, accountIds: raw.accountIds || [], accounts: resolve(raw.accountIds || []) };
  }

  async function load() {
    if (loading) return;
    loading = true;
    try {
      const res = await fetch("/api/saved-lists", { cache: "no-store" });
      const data = await res.json();
      lists = (data.lists || []).map(hydrate);
      loaded = true;
      emit();
    } catch (e) {
      console.log("[v0] saved-lists load failed:", e && e.message);
    } finally {
      loading = false;
    }
  }

  return {
    get: () => lists,
    isLoaded: () => loaded,
    ensureLoaded: () => { if (!loaded && !loading) load(); },
    reload: load,
    subscribe: (fn) => { subs.add(fn); return () => subs.delete(fn); },

    create: async (name, accounts) => {
      const accountIds = accounts.map(a => a.id);
      // Generate a real UUID up front so the optimistic id is the persisted id.
      // This avoids the temp-id swap that previously dropped the open list view
      // and sent invalid (non-uuid) listIds when posting to referrals.
      const id = (window.crypto && window.crypto.randomUUID)
        ? window.crypto.randomUUID()
        : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
            const r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8;
            return v.toString(16);
          });
      lists = [hydrate({ id, name: name.trim() || "Untitled list", createdAt: Date.now(), accountIds }), ...lists];
      emit();
      try {
        const res = await fetch("/api/saved-lists", {
          method: "POST", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ id, name, accountIds }),
        });
        const data = await res.json();
        if (data.list) lists = lists.map(l => l.id === id ? hydrate(data.list) : l);
        emit();
      } catch (e) { console.log("[v0] create list failed:", e && e.message); load(); }
      return id;
    },

    addTo: async (id, accounts) => {
      const add = accounts.map(a => a.id);
      lists = lists.map(l => l.id === id ? hydrate({ ...l, accountIds: Array.from(new Set([...l.accountIds, ...add])) }) : l);
      emit();
      try {
        const res = await fetch("/api/saved-lists/" + id, {
          method: "PATCH", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ add }),
        });
        const data = await res.json();
        if (data.accountIds) lists = lists.map(l => l.id === id ? hydrate({ ...l, accountIds: data.accountIds }) : l);
        emit();
      } catch (e) { console.log("[v0] addTo failed:", e && e.message); load(); }
    },

    remove: async (id) => {
      lists = lists.filter(l => l.id !== id);
      emit();
      try { await fetch("/api/saved-lists/" + id, { method: "DELETE" }); }
      catch (e) { console.log("[v0] remove list failed:", e && e.message); load(); }
    },

    removeAccount: async (id, acc) => {
      lists = lists.map(l => l.id === id ? hydrate({ ...l, accountIds: l.accountIds.filter(x => x !== acc.id) }) : l);
      emit();
      try {
        await fetch("/api/saved-lists/" + id, {
          method: "PATCH", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ remove: [acc.id] }),
        });
      } catch (e) { console.log("[v0] removeAccount failed:", e && e.message); load(); }
    },
  };
})();

function useSavedLists() {
  const [, force] = useState(0);
  useEffect(() => {
    const unsub = SavedListsStore.subscribe(() => force(n => n + 1));
    SavedListsStore.ensureLoaded();
    return unsub;
  }, []);
  return SavedListsStore;
}


/* ---------- FILTERS ----------------------------------------------------- */
const EMPTY_FILTERS = {
  score: { min: "", max: "" },
  onlineRev: { min: "", max: "" },
  sku: { min: "", max: "" },
  employees: { min: "", max: "" },
  shopify: "any",   // any | yes | no
  warmPath: "any",  // any | yes | no
  vendors: [],      // e.g. ["Algolia", "Nosto"]
  stages: [],       // e.g. ["lead", "customer"]
};

const NUMERIC_FIELDS = [
  { key: "score", label: "ICP score", suffix: "", placeholder: ["0", "100"] },
  { key: "onlineRev", label: "Online revenue ($M)", suffix: "M", placeholder: ["0", "any"] },
  { key: "sku", label: "SKU count", suffix: "", placeholder: ["0", "any"] },
  { key: "employees", label: "Employees", suffix: "", placeholder: ["0", "any"] },
];
const VENDOR_OPTIONS = ["Algolia", "Nosto", "Rebuy", "RichRelevance"];

function countActiveFilters(f) {
  let n = 0;
  NUMERIC_FIELDS.forEach(({ key }) => { if (f[key].min !== "" || f[key].max !== "") n++; });
  if (f.shopify !== "any") n++;
  if (f.warmPath !== "any") n++;
  if (f.vendors.length) n++;
  if (f.stages.length) n++;
  return n;
}

function passesFilters(a, f) {
  for (const { key } of NUMERIC_FIELDS) {
    const v = a[key] || 0;
    const { min, max } = f[key];
    if (min !== "" && v < parseFloat(min)) return false;
    if (max !== "" && v > parseFloat(max)) return false;
  }
  if (f.shopify === "yes" && !a.shopify) return false;
  if (f.shopify === "no" && a.shopify) return false;
  const hasWarm = a.warmIntro && a.warmIntro.degree > 0;
  if (f.warmPath === "yes" && !hasWarm) return false;
  if (f.warmPath === "no" && hasWarm) return false;
  if (f.vendors.length) {
    const names = (a.vendors || []).map(v => v.name);
    if (!f.vendors.some(want => names.includes(want))) return false;
  }
  if (f.stages.length && !f.stages.includes(a.engagement.status)) return false;
  return true;
}

function FilterPopover({ filters, setFilters, stageOptions, resultCount, onClose }) {
  const ref = useRef(null);
  useEffect(() => {
    function onDoc(e) { if (ref.current && !ref.current.contains(e.target)) onClose(); }
    function onEsc(e) { if (e.key === "Escape") onClose(); }
    document.addEventListener("mousedown", onDoc);
    document.addEventListener("keydown", onEsc);
    return () => { document.removeEventListener("mousedown", onDoc); document.removeEventListener("keydown", onEsc); };
  }, [onClose]);

  const setNum = (key, bound, val) =>
    setFilters(f => ({ ...f, [key]: { ...f[key], [bound]: val.replace(/[^0-9.]/g, "") } }));
  const toggleArr = (key, val) =>
    setFilters(f => ({ ...f, [key]: f[key].includes(val) ? f[key].filter(x => x !== val) : [...f[key], val] }));
  const active = countActiveFilters(filters);

  return (
    <div className="filter-pop" ref={ref}>
      <div className="filter-pop-head">
        <span>Filters</span>
        {active > 0 && <button className="filter-clear" onClick={() => setFilters({ ...EMPTY_FILTERS })}>Clear all</button>}
      </div>

      <div className="filter-pop-body">
        {NUMERIC_FIELDS.map(({ key, label, suffix, placeholder }) => (
          <div className="filter-field" key={key}>
            <label>{label}</label>
            <div className="filter-range">
              <input inputMode="decimal" placeholder={"min " + placeholder[0]} value={filters[key].min}
                onChange={e => setNum(key, "min", e.target.value)} />
              <span className="filter-dash">–</span>
              <input inputMode="decimal" placeholder={"max " + placeholder[1]} value={filters[key].max}
                onChange={e => setNum(key, "max", e.target.value)} />
              {suffix && <span className="filter-suffix">{suffix}</span>}
            </div>
          </div>
        ))}

        <div className="filter-field">
          <label>Shopify store</label>
          <div className="seg filter-seg">
            {[["any", "Any"], ["yes", "Shopify"], ["no", "Non-Shopify"]].map(([v, l]) => (
              <button key={v} className={filters.shopify === v ? "on" : ""} onClick={() => setFilters(f => ({ ...f, shopify: v }))}>{l}</button>
            ))}
          </div>
        </div>

        <div className="filter-field">
          <label>Warm path</label>
          <div className="seg filter-seg">
            {[["any", "Any"], ["yes", "Has intro"], ["no", "Cold"]].map(([v, l]) => (
              <button key={v} className={filters.warmPath === v ? "on" : ""} onClick={() => setFilters(f => ({ ...f, warmPath: v }))}>{l}</button>
            ))}
          </div>
        </div>

        <div className="filter-field">
          <label>Competing stack <span className="filter-hint">matches any selected</span></label>
          <div className="filter-chips">
            {VENDOR_OPTIONS.map(v => (
              <button key={v} className={"filter-chip" + (filters.vendors.includes(v) ? " on" : "")} onClick={() => toggleArr("vendors", v)}>{v}</button>
            ))}
          </div>
        </div>

        {stageOptions.length > 0 && (
          <div className="filter-field">
            <label>Stage</label>
            <div className="filter-chips">
              {stageOptions.map(s => (
                <button key={s} className={"filter-chip" + (filters.stages.includes(s) ? " on" : "")} onClick={() => toggleArr("stages", s)}>{s}</button>
              ))}
            </div>
          </div>
        )}
      </div>

      <div className="filter-pop-foot">
        <span className="subtle">{resultCount.toLocaleString()} accounts match</span>
        <button className="btn sm pri" onClick={onClose}>Done</button>
      </div>
    </div>
  );
}

function Kpis() {
  const A = window.ICP.ACCOUNTS;
  const hot = A.filter(a => a.engagement.status === "hot").length;
  const warmPaths = A.filter(a => a.warmIntro.degree > 0).length;
  const liveSignals = A.reduce((n, a) => n + a.signals.filter(s => s.heat === "hot").length, 0);
  const gaps = A.filter(a => a.people.length < 2 || a.engagement.owner === "—").length;
  const k = [
    { v: window.ICP.META.totalList.toLocaleString(), l: "Accounts in ICP list", d: <span className="muted">{window.ICP.META.workingShown} shown · synced from HubSpot</span>, ic: "building" },
    { v: hot, l: "Hot accounts this week", d: <span className="up"><Icon name="up" size={12} style={{ verticalAlign: -1 }} /> 2 vs last 7d</span>, ic: "trend" },
    { v: liveSignals, l: "Red-hot signals (7d)", d: <span className="muted">vendor swaps + new hires</span>, ic: "signal" },
    { v: gaps, l: "Coverage gaps", d: <span className="down">need People Map / owner</span>, ic: "flag" },
  ];
  return (
    <div className="kpis">
      {k.map((x, i) => (
        <div className="kpi" key={i}>
          <div className="between">
            <span className="label-micro">{x.l}</span>
            <Icon name={x.ic} size={16} style={{ color: "var(--fg-subtle)" }} />
          </div>
          <div className="v mt8">{x.v}</div>
          <div className="d">{x.d}</div>
        </div>
      ))}
    </div>
  );
}

function VendorChips({ vendors, max }) {
  const shown = max ? vendors.slice(0, max) : vendors;
  return (
    <div className="vend-row">
      {shown.map((v, i) => (
        <span className={"vend" + (v.status === "expiring" ? " exp" : "")} key={i} title={v.category + (v.note ? " · " + v.note : "")}>
          {v.name}{v.status === "expiring" ? " ⚠" : ""}
        </span>
      ))}
      {max && vendors.length > max ? <span className="vend">+{vendors.length - max}</span> : null}
    </div>
  );
}

/* ---------- TABLE layout ------------------------------------------------ */
function TableLayout({ accounts, enrich, onOpen, sort, setSort, selected, onToggle, onToggleAll }) {
  const I = window.ICP;
  const allSelected = accounts.length > 0 && accounts.every(a => selected.has(a));
  const someSelected = !allSelected && accounts.some(a => selected.has(a));
  const headRef = useRef(null);
  useEffect(() => { if (headRef.current) headRef.current.indeterminate = someSelected; }, [someSelected]);
  const SortTh = ({ k, children, num }) => (
    <th className={num ? "num" : ""} onClick={() => setSort(s => ({ key: k, dir: s.key === k && s.dir === "desc" ? "asc" : "desc" }))}
        style={{ cursor: "pointer" }}>
      <span style={{ display: "inline-flex", gap: 4, alignItems: "center" }}>
        {children}{sort.key === k ? <Icon name={sort.dir === "desc" ? "chevD" : "chevD"} size={11} style={{ transform: sort.dir === "asc" ? "rotate(180deg)" : "none", color: "var(--c-malachyte)" }} /> : null}
      </span>
    </th>
  );
  return (
    <div className="card" style={{ overflow: "hidden" }}>
      <div style={{ overflowX: "auto" }}>
        <table className="tbl">
          <thead>
            <tr>
              <th style={{ width: 34 }}>
                <input ref={headRef} type="checkbox" className="row-check" checked={allSelected}
                  onChange={() => onToggleAll(!allSelected)} aria-label="Select all accounts" />
              </th>
              <th style={{ width: 30 }}>#</th>
              <SortTh k="score">Account</SortTh>
              <SortTh k="score" num>ICP</SortTh>
              <th>Tier</th>
              <SortTh k="onlineRev" num>Online rev</SortTh>
              <SortTh k="sku" num>SKU #</SortTh>
              {enrich !== "minimal" && <th>Competing stack</th>}
              <th>Shopify</th>
              {enrich === "rich" && <SortTh k="visits" num>Traffic</SortTh>}
              <th>Warm path</th>
              {enrich !== "minimal" && <th>Top signal</th>}
              <th>Stage</th>
            </tr>
          </thead>
          <tbody>
            {accounts.map((a, i) => (
              <tr key={a.id + "-" + i} className={selected.has(a) ? "row-selected" : ""} onClick={() => onOpen(a)}>
                <td onClick={e => e.stopPropagation()}>
                  <input type="checkbox" className="row-check" checked={selected.has(a)}
                    onChange={() => onToggle(a)} aria-label={"Select " + a.brand} />
                </td>
                <td className="rank">{i + 1}</td>
                <td>
                  <div className="acct-cell">
                    <Logo name={a.brand} src={a.logo} />
                    <div style={{ minWidth: 0 }}>
                      <div className="nm">{a.brand}</div>
                      <div className="dm">{a.vertical.split("→")[0].trim()}</div>
                    </div>
                  </div>
                </td>
                <td className="num"><ScoreCell value={a.score} /></td>
                <td><Tier t={a.tier} /></td>
                <td className="num">{I.fmtMoney(a.onlineRev)}</td>
                <td className="num">{a.sku > 0 ? a.sku.toLocaleString() : <span className="subtle">—</span>}</td>
                {enrich !== "minimal" && <td><VendorChips vendors={a.vendors} max={enrich === "rich" ? 3 : 2} /></td>}
                <td>
                  {a.shopify
                    ? <span className="chip" style={{ background: "rgba(149,191,110,0.16)", color: "#4a7a2b", fontWeight: 500 }}>Shopify</span>
                    : <span className="subtle" style={{ fontSize: 12 }}>—</span>}
                </td>
                {enrich === "rich" && <td className="num">{a.visits}M</td>}
                <td>
                  {a.warmIntro.degree > 0
                    ? <span className="chip" style={{ background: "var(--bg-accent-soft)", color: "var(--c-malachyte-dark)" }} title={a.warmIntro.via}><Icon name="link" size={12} />{a.warmIntro.introducer}</span>
                    : <span className="subtle" style={{ fontSize: 12 }}>— cold</span>}
                </td>
                {enrich !== "minimal" && <td style={{ maxWidth: 180 }}>
                  {a.signals[0]
                    ? <div className="row gap6"><HeatDot heat={a.signals[0].heat} /><span style={{ fontSize: 12, color: "var(--wf-muted)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", display: "block" }}>{a.signals[0].text}</span></div>
                    : <span className="subtle" style={{ fontSize: 12 }}>—</span>}
                </td>}
                <td><StatusChip status={a.engagement.status} /></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

/* ---------- CARDS layout ------------------------------------------------ */
function CardsLayout({ accounts, enrich, onOpen }) {
  const I = window.ICP;
  return (
    <div className="grid-cards">
      {accounts.map((a, i) => (
        <div className="card acard" key={a.id + "-" + i} onClick={() => onOpen(a)}>
          <div className="head">
            <Logo name={a.brand} src={a.logo} size="lg" />
            <div className="meta">
              <div className="between">
                <span style={{ fontWeight: 500, fontSize: 15 }}>{a.brand}</span>
                <Tier t={a.tier} />
              </div>
              <div className="dm subtle" style={{ fontSize: 12 }}>{a.vertical}</div>
            </div>
          </div>
          <div>
            <div className="between" style={{ marginBottom: 5 }}>
              <span className="label-micro">ICP score</span>
              <span className="score-num">{a.score}</span>
            </div>
            <ScoreCell value={a.score} width="100%" hideNum />
          </div>
          <div className="stat-row">
            <div className="stat"><span className="subtle">Online rev</span><b>{I.fmtMoney(a.onlineRev)}</b></div>
            {enrich !== "minimal" && <div className="stat"><span className="subtle">Traffic</span><b>{a.visits}M</b></div>}
            {enrich === "rich" && <div className="stat"><span className="subtle">SKUs</span><b>{(a.sku/1000).toFixed(1)}k</b></div>}
            <div className="stat"><span className="subtle">Impact (mid)</span><b>${a.impact.mid}M</b></div>
          </div>
          {enrich !== "minimal" && <VendorChips vendors={a.vendors} max={3} />}
          <div className="between" style={{ borderTop: "1px solid #F0EDE7", paddingTop: 10, marginTop: 2 }}>
            {a.warmIntro.degree > 0
              ? <span className="chip" style={{ background: "var(--bg-accent-soft)", color: "var(--c-malachyte-dark)" }}><Icon name="link" size={12} />{a.warmIntro.introducer}</span>
              : <span className="subtle" style={{ fontSize: 12 }}>No warm path</span>}
            <StatusChip status={a.engagement.status} />
          </div>
        </div>
      ))}
    </div>
  );
}

/* ---------- TIERS layout (kanban) -------------------------------------- */
function TiersLayout({ accounts, enrich, onOpen }) {
  const I = window.ICP;
  const tiers = ["T1", "T2", "T3"];
  const meta = {
    T1: { label: "Tier 1 · $25–50M · $50k", note: "Founder-led · 30-day cycle" },
    T2: { label: "Tier 2 · $50–300M · $100k", note: "AE-led · 60–90 day cycle" },
    T3: { label: "Tier 3 · $300M–1.5B · $250k+", note: "Multi-threaded · 90–180 day" },
  };
  return (
    <div className="tiers">
      {tiers.map(t => {
        const list = accounts.filter(a => a.tier === t);
        return (
          <div className="tier-col" key={t}>
            <div className="head">
              <Tier t={t} />
              <div style={{ flex: 1 }}>
                <div style={{ fontWeight: 500, fontSize: 12.5 }}>{meta[t].label}</div>
                <div className="subtle" style={{ fontSize: 11 }}>{meta[t].note}</div>
              </div>
              <span className="subtle" style={{ fontSize: 12 }}>{list.length}</span>
            </div>
            <div className="stack">
              {list.map((a, i) => (
                <div className="tier-mini" key={a.id + "-" + i} onClick={() => onOpen(a)}>
                  <div className="row gap10" style={{ alignItems: "flex-start" }}>
                    <Logo name={a.brand} src={a.logo} size="sm" />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div className="between">
                        <span style={{ fontWeight: 500, fontSize: 13 }}>{a.brand}</span>
                        <span className="score-num">{a.score}</span>
                      </div>
                      <div className="subtle" style={{ fontSize: 11 }}>{I.fmtMoney(a.onlineRev)} · {a.vertical.split("→")[0].trim()}</div>
                    </div>
                  </div>
                  {enrich !== "minimal" && <div className="mt8"><ScoreCell value={a.score} width="100%" hideNum /></div>}
                  <div className="between mt8">
                    {a.warmIntro.degree > 0
                      ? <span className="chip sm" style={{ fontSize: 10.5, background: "var(--bg-accent-soft)", color: "var(--c-malachyte-dark)", padding: "1px 7px" }}><Icon name="link" size={10} />{a.warmIntro.introducer.split(" ")[0]}</span>
                      : <span className="subtle" style={{ fontSize: 11 }}>cold</span>}
                    <StatusChip status={a.engagement.status} />
                  </div>
                </div>
              ))}
              {list.length === 0 && <div className="empty" style={{ padding: 20, fontSize: 12 }}>No accounts</div>}
            </div>
          </div>
        );
      })}
    </div>
  );
}

/* ---------- Add-to-list modal ------------------------------------------- */
function AddToListModal({ accounts, store, onClose }) {
  const lists = store.get();
  const [mode, setMode] = useState(lists.length ? "existing" : "new");
  const [name, setName] = useState("");
  const [targetId, setTargetId] = useState(lists[0] ? lists[0].id : "");
  const ref = useRef(null);
  useEffect(() => {
    function onEsc(e) { if (e.key === "Escape") onClose(); }
    document.addEventListener("keydown", onEsc);
    return () => document.removeEventListener("keydown", onEsc);
  }, [onClose]);

  const save = () => {
    if (mode === "new") store.create(name, accounts);
    else if (targetId) store.addTo(targetId, accounts);
    onClose();
  };

  return (
    <div className="modal-scrim" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" ref={ref} role="dialog" aria-label="Add to saved list">
        <div className="modal-head">
          <h3>Add {accounts.length.toLocaleString()} {accounts.length === 1 ? "account" : "accounts"} to a list</h3>
          <button className="btn ghost sm" onClick={onClose} aria-label="Close"><Icon name="x" size={16} /></button>
        </div>
        <div className="modal-body">
          {lists.length > 0 && (
            <div className="seg filter-seg" style={{ marginBottom: 12 }}>
              <button className={mode === "existing" ? "on" : ""} onClick={() => setMode("existing")}>Existing list</button>
              <button className={mode === "new" ? "on" : ""} onClick={() => setMode("new")}>New list</button>
            </div>
          )}
          {mode === "new" ? (
            <div className="filter-field">
              <label>List name</label>
              <input className="modal-input" autoFocus placeholder="e.g. Q3 Nosto swap targets"
                value={name} onChange={e => setName(e.target.value)}
                onKeyDown={e => { if (e.key === "Enter") save(); }} />
            </div>
          ) : (
            <div className="saved-pick">
              {lists.map(l => (
                <button key={l.id} className={"saved-pick-row" + (targetId === l.id ? " on" : "")} onClick={() => setTargetId(l.id)}>
                  <span className="row gap8"><Icon name="list" size={15} />{l.name}</span>
                  <span className="subtle" style={{ fontSize: 12 }}>{l.accounts.length}</span>
                </button>
              ))}
            </div>
          )}
        </div>
        <div className="modal-foot">
          <button className="btn sm ghost" onClick={onClose}>Cancel</button>
          <button className="btn sm pri" onClick={save} disabled={mode === "new" ? !name.trim() : !targetId}>
            <Icon name="plus" size={14} />{mode === "new" ? "Create & add" : "Add to list"}
          </button>
        </div>
      </div>
    </div>
  );
}

/* ---------- Post-list-to-referrals modal -------------------------------- */
function PostListModal({ list, alreadyPosted, onPosted, onClose }) {
  const [desc, setDesc] = useState("");
  const [done, setDone] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState("");
  const [notify, setNotify] = useState(true);
  useEffect(() => {
    function onEsc(e) { if (e.key === "Escape") onClose(); }
    document.addEventListener("keydown", onEsc);
    return () => document.removeEventListener("keydown", onEsc);
  }, [onClose]);

  const count = list.accounts ? list.accounts.length : (list.accountIds || []).length;

  const submit = async () => {
    setSubmitting(true);
    setError("");
    try {
      const res = await fetch("/api/referrals", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ kind: "list", listId: list.id, listName: list.name, accountCount: count, description: desc, notify }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok || data.error) throw new Error(data.error || ("Request failed (" + res.status + ")"));
      setDone(true);
      if (onPosted) onPosted();
    } catch (e) {
      console.log("[v0] post list to referrals failed:", e && e.message);
      setError("Couldn't post to referrals. Please try again.");
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <div className="modal-scrim" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" role="dialog" aria-label="Post list to referrals">
        {done ? (
          <>
            <div className="modal-body" style={{ textAlign: "center", padding: "28px 24px" }}>
              <div className="intro-check"><Icon name="check" size={22} /></div>
              <h3 style={{ marginTop: 12 }}>Posted to referrals</h3>
              <p className="subtle" style={{ marginTop: 6 }}><b>{list.name}</b> ({count.toLocaleString()} {count === 1 ? "account" : "accounts"}) has been posted to the referral board.</p>
            </div>
            <div className="modal-foot" style={{ justifyContent: "center" }}>
              <button className="btn sm pri" onClick={onClose}>Done</button>
            </div>
          </>
        ) : (
          <>
            <div className="modal-head">
              <h3>Post “{list.name}” to referrals</h3>
              <button className="btn ghost sm" onClick={onClose} aria-label="Close"><Icon name="x" size={16} /></button>
            </div>
            <div className="modal-body">
              {alreadyPosted && (
                <div className="banner info" style={{ marginBottom: 14 }}>
                  <Icon name="check" size={15} style={{ color: "var(--st-info)" }} />
                  <span>This list is already on the referral board. Posting again will add a new entry.</span>
                </div>
              )}
              <p className="subtle" style={{ marginBottom: 14 }}>
                Share this list of <b>{count.toLocaleString()}</b> {count === 1 ? "account" : "accounts"} to the referral board. Add an optional note about what kind of intros you’re after.
              </p>
              <div className="filter-field">
                <label>Description <span className="subtle" style={{ fontWeight: 400 }}>(optional)</span></label>
                <textarea className="modal-input" rows={4} autoFocus
                  placeholder="e.g. These are Nosto-swap targets — looking for warm paths into ecommerce or growth leadership."
                  value={desc} onChange={e => setDesc(e.target.value)}
                  style={{ resize: "vertical", lineHeight: 1.5 }} />
              </div>
              <label className="notify-row" style={{ display: "flex", alignItems: "flex-start", gap: 10, marginTop: 14, cursor: "pointer" }}>
                <input type="checkbox" checked={notify} onChange={e => setNotify(e.target.checked)} style={{ marginTop: 2, accentColor: "var(--c-malachyte)", width: 16, height: 16, flexShrink: 0 }} />
                <span style={{ fontSize: 13, lineHeight: 1.45 }}>
                  Notify referral partners that this list was posted
                  <span className="subtle" style={{ display: "block", fontWeight: 400 }}>Partners get a heads-up so they can tag companies they have connections to.</span>
                </span>
              </label>
              {error && (
                <p style={{ color: "var(--c-danger, #D84040)", fontSize: 13, marginTop: 12 }} role="alert">{error}</p>
              )}
            </div>
            <div className="modal-foot">
              <button className="btn sm ghost" onClick={onClose}>Cancel</button>
              <button className="btn sm pri" onClick={submit} disabled={submitting}><Icon name="share" size={14} />{submitting ? "Posting…" : "Post to referrals"}</button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

function ListView({ tweaks, onOpen }) {
  const I = window.ICP;
  const [q, setQ] = useState("");
  const [tierFilter, setTierFilter] = useState("all");
  const [sort, setSort] = useState({ key: "score", dir: "desc" });
  const [filters, setFilters] = useState({ ...EMPTY_FILTERS });
  const [showFilters, setShowFilters] = useState(false);
  const [selected, setSelected] = useState(() => new Set());
  const [showAddModal, setShowAddModal] = useState(false);
  const store = useSavedLists();

  const toggleOne = (a) => setSelected(prev => {
    const next = new Set(prev);
    next.has(a) ? next.delete(a) : next.add(a);
    return next;
  });

  const stageOptions = useMemo(
    () => Array.from(new Set(I.ACCOUNTS.map(a => a.engagement.status).filter(s => s && s !== "—"))).sort(),
    []
  );

  const accounts = useMemo(() => {
    let a = I.ACCOUNTS.slice();
    if (q) a = a.filter(x => (x.brand + x.vertical + x.parent).toLowerCase().includes(q.toLowerCase()));
    if (tierFilter !== "all") a = a.filter(x => x.tier === tierFilter);
    a = a.filter(x => passesFilters(x, filters));
    a.sort((x, y) => {
      const dir = sort.dir === "desc" ? -1 : 1;
      return (x[sort.key] - y[sort.key]) * dir;
    });
    return a;
  }, [q, tierFilter, sort, filters]);

  const activeFilterCount = countActiveFilters(filters);

  const toggleAll = (selectAll) => setSelected(prev => {
    const next = new Set(prev);
    accounts.forEach(a => selectAll ? next.add(a) : next.delete(a));
    return next;
  });
  const selectedCount = useMemo(() => accounts.filter(a => selected.has(a)).length, [accounts, selected]);

  const layout = tweaks.layout;
  const enrich = tweaks.enrichment;

  return (
    <div className="page">
      <Kpis />

      <div className="sec-head">
        <h2>Ranked target list</h2>
        <span className="chip" style={{ background: "var(--bg-accent-soft)", color: "var(--c-malachyte-dark)" }} title="Last successful HubSpot sync"><span className="dot" style={{ background: "var(--c-malachyte)" }}></span>HubSpot · synced {I.META.lastSync}</span>
        <span className="line"></span>
      </div>

      <div className="between wrap" style={{ marginBottom: 14, gap: 10 }}>
        <div className="row gap10 wrap">
          <div className="search">
            <Icon name="search" />
            <input placeholder="Search accounts, verticals…" value={q} onChange={e => setQ(e.target.value)} />
          </div>
          <div className="seg">
            {["all", "T1", "T2", "T3"].map(t => (
              <button key={t} className={tierFilter === t ? "on" : ""} onClick={() => setTierFilter(t)}>{t === "all" ? "All tiers" : t}</button>
            ))}
          </div>
        </div>
        <div className="row gap8">
          {selectedCount > 0 ? (
            <>
              <span className="sel-count">{selectedCount.toLocaleString()} selected</span>
              <button className="btn sm"><Icon name="download" size={14} />Export</button>
              <button className="btn sm pri" onClick={() => setShowAddModal(true)}><Icon name="plus" size={14} />Add to list</button>
              <button className="btn sm ghost" onClick={() => setSelected(new Set())}>Clear</button>
            </>
          ) : (
            <span className="subtle" style={{ fontSize: 12 }}>{accounts.length.toLocaleString()} accounts</span>
          )}
          <div className="filter-anchor">
            <button className={"btn sm" + (activeFilterCount ? " filter-on" : "")} onClick={() => setShowFilters(s => !s)}>
              <Icon name="filter" size={14} />Filters
              {activeFilterCount > 0 && <span className="filter-badge">{activeFilterCount}</span>}
            </button>
            {showFilters && (
              <FilterPopover filters={filters} setFilters={setFilters} stageOptions={stageOptions}
                resultCount={accounts.length} onClose={() => setShowFilters(false)} />
            )}
          </div>
        </div>
      </div>

      {layout === "table" && <TableLayout accounts={accounts} enrich={enrich} onOpen={onOpen} sort={sort} setSort={setSort} selected={selected} onToggle={toggleOne} onToggleAll={toggleAll} />}
      {layout === "cards" && <CardsLayout accounts={accounts} enrich={enrich} onOpen={onOpen} />}
      {layout === "tiers" && <TiersLayout accounts={accounts} enrich={enrich} onOpen={onOpen} />}

      <div className="banner info mt20">
        <Icon name="refresh" size={16} style={{ color: "var(--st-info)" }} />
        <span>Regenerated daily from <b>{I.META.source}</b>. Sources: {I.META.sources.join(" · ")}. Tier-up / tier-down diffs post to <span className="mono">#gtm-pipeline</span>.</span>
      </div>

      {showAddModal && (
        <AddToListModal accounts={accounts.filter(a => selected.has(a))} store={store}
          onClose={() => { setShowAddModal(false); setSelected(new Set()); }} />
      )}
    </div>
  );
}

/* ---------- SAVED LISTS view -------------------------------------------- */
function SavedListsView({ onOpen }) {
  const I = window.ICP;
  const store = useSavedLists();
  const lists = store.get();
  const [activeId, setActiveId] = useState(null);
  const active = lists.find(l => l.id === activeId) || null;

  const [q, setQ] = useState("");
  const [tierFilter, setTierFilter] = useState("all");
  const [filters, setFilters] = useState(EMPTY_FILTERS);
  const [showFilters, setShowFilters] = useState(false);
  const [sort, setSort] = useState({ key: "score", dir: "desc" });
  const [selected, setSelected] = useState(() => new Set());
  const [showAddModal, setShowAddModal] = useState(false);
  const [showPostModal, setShowPostModal] = useState(false);
  const [postedListIds, setPostedListIds] = useState(() => new Set());

  // Which lists have already been posted to the referral board.
  const refreshPosted = useCallback(() => {
    fetch("/api/referrals")
      .then(r => r.json())
      .then(d => {
        const ids = (d.referrals || []).filter(r => r.kind === "list" && r.listId).map(r => r.listId);
        setPostedListIds(new Set(ids));
      })
      .catch(e => console.log("[v0] load posted referrals failed:", e && e.message));
  }, []);
  useEffect(() => { refreshPosted(); }, [refreshPosted]);
  const alreadyPosted = active ? postedListIds.has(active.id) : false;

  const reset = () => { setQ(""); setTierFilter("all"); setFilters(EMPTY_FILTERS); setShowFilters(false); setSelected(new Set()); };
  const goBack = () => { setActiveId(null); reset(); };
  const openList = (id) => { setActiveId(id); reset(); };

  const stageOptions = useMemo(
    () => Array.from(new Set(I.ACCOUNTS.map(a => a.engagement.status).filter(s => s && s !== "—"))).sort(),
    [I]
  );

  const visible = useMemo(() => {
    if (!active) return [];
    let a = active.accounts.slice();
    if (tierFilter !== "all") a = a.filter(x => x.tier === tierFilter);
    if (q.trim()) {
      const t = q.toLowerCase();
      a = a.filter(x => (x.brand + x.vertical + x.parent).toLowerCase().includes(t));
    }
    a = a.filter(x => passesFilters(x, filters));
    a.sort((x, y) => ((x[sort.key] || 0) - (y[sort.key] || 0)) * (sort.dir === "desc" ? -1 : 1));
    return a;
  }, [active, q, tierFilter, filters, sort]);

  const activeFilterCount = countActiveFilters(filters);

  const toggleOne = (a) => setSelected(prev => { const n = new Set(prev); n.has(a) ? n.delete(a) : n.add(a); return n; });
  const toggleAll = (on) => setSelected(prev => { const n = new Set(prev); visible.forEach(a => on ? n.add(a) : n.delete(a)); return n; });
  const selectedCount = useMemo(() => visible.filter(a => selected.has(a)).length, [visible, selected]);

  if (lists.length === 0) {
    return (
      <div className="page">
        <div className="empty-state card">
          <Icon name="list" size={28} style={{ color: "var(--fg-subtle)" }} />
          <h3>No saved lists yet</h3>
          <p className="subtle">Select accounts in the Ranked accounts tab and choose <b>Add to list</b> to build a saved ICP list here.</p>
        </div>
      </div>
    );
  }

  if (active) {
    return (
      <div className="page">
        <div className="saved-detail-head">
          <button className="btn sm ghost" onClick={goBack}><Icon name="chevL" size={15} />All lists</button>
          <div className="saved-title-wrap">
            <div className="row gap8">
              <Icon name="list" size={18} style={{ color: "var(--c-malachyte)" }} />
              <h2 className="saved-title">{active.name}</h2>
            </div>
            <span className="subtle" style={{ fontSize: 12 }}>{active.accounts.length.toLocaleString()} accounts · saved list</span>
          </div>
          <span className="spacer" style={{ flex: 1 }}></span>
          {alreadyPosted && (
            <span className="referral-posted-badge" title="This list has already been posted to the referral board">
              <Icon name="check" size={13} />Referral posted
            </span>
          )}
          <button className="btn sm pri" onClick={() => setShowPostModal(true)}>
            <Icon name="share" size={14} />{alreadyPosted ? "Post again" : "Post to referrals"}
          </button>
        </div>

        <div className="between wrap" style={{ marginBottom: 14, gap: 10 }}>
          <div className="row gap10 wrap">
            <div className="search">
              <Icon name="search" />
              <input placeholder="Search this list…" value={q} onChange={e => setQ(e.target.value)} />
            </div>
            <div className="seg">
              {["all", "T1", "T2", "T3"].map(t => (
                <button key={t} className={tierFilter === t ? "on" : ""} onClick={() => setTierFilter(t)}>{t === "all" ? "All tiers" : t}</button>
              ))}
            </div>
          </div>
          <div className="row gap8">
            {selectedCount > 0 ? (
              <>
                <span className="sel-count">{selectedCount.toLocaleString()} selected</span>
                <button className="btn sm pri" onClick={() => setShowAddModal(true)}><Icon name="plus" size={14} />Save as new list</button>
                <button className="btn sm ghost" onClick={() => {
                  visible.filter(a => selected.has(a)).forEach(a => store.removeAccount(active.id, a));
                  setSelected(new Set());
                }}><Icon name="x" size={14} />Remove from list</button>
                <button className="btn sm ghost" onClick={() => setSelected(new Set())}>Clear</button>
              </>
            ) : (
              <span className="subtle" style={{ fontSize: 12 }}>{visible.length.toLocaleString()} {visible.length === 1 ? "account" : "accounts"}</span>
            )}
            <div className="filter-anchor">
              <button className={"btn sm" + (activeFilterCount ? " filter-on" : "")} onClick={() => setShowFilters(s => !s)}>
                <Icon name="filter" size={14} />Filters
                {activeFilterCount > 0 && <span className="filter-badge">{activeFilterCount}</span>}
              </button>
              {showFilters && (
                <FilterPopover filters={filters} setFilters={setFilters} stageOptions={stageOptions}
                  resultCount={visible.length} onClose={() => setShowFilters(false)} />
              )}
            </div>
          </div>
        </div>

        {visible.length === 0 ? (
          <div className="empty-state card"><Icon name="search" size={24} style={{ color: "var(--fg-subtle)" }} /><h3>No matching accounts</h3><p className="subtle">No accounts in this list match your search or filters.</p></div>
        ) : (
          <TableLayout accounts={visible} enrich="rich" onOpen={onOpen} sort={sort} setSort={setSort}
            selected={selected} onToggle={toggleOne} onToggleAll={toggleAll} />
        )}

        {showAddModal && (
          <AddToListModal accounts={visible.filter(a => selected.has(a))} store={store}
            onClose={() => { setShowAddModal(false); setSelected(new Set()); }} />
        )}
        {showPostModal && (
          <PostListModal list={active} alreadyPosted={alreadyPosted}
            onPosted={refreshPosted}
            onClose={() => setShowPostModal(false)} />
        )}
      </div>
    );
  }

  return (
    <div className="page">
      <div className="grid-cards">
        {lists.map(l => (
          <div className="card acard saved-card" key={l.id} onClick={() => openList(l.id)}>
            <div className="between">
              <span className="row gap8" style={{ fontWeight: 600, fontSize: 15 }}><Icon name="list" size={16} style={{ color: "var(--c-malachyte)" }} />{l.name}</span>
              <button className="btn ghost sm" onClick={e => { e.stopPropagation(); store.remove(l.id); }} aria-label="Delete list"><Icon name="trash" size={14} /></button>
            </div>
            <div className="v" style={{ fontSize: 30, marginTop: 6 }}>{l.accounts.length}</div>
            <div className="subtle" style={{ fontSize: 12 }}>accounts saved</div>
            <div className="saved-logos">
              {l.accounts.slice(0, 6).map((a, i) => <Logo key={i} name={a.brand} src={a.logo} size="sm" />)}
              {l.accounts.length > 6 && <span className="subtle" style={{ fontSize: 11, alignSelf: "center" }}>+{l.accounts.length - 6}</span>}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, { ListView, SavedListsView });
