// Deal Pipeline screen — real targets from 8 module PDFs.
// Every column header supports both sort + filter (like Status) via a unified popover.

function PipelineScreen({ scope }) {
  const F = window.VAULT_FIRM;
  const { useState, useEffect, useMemo, useRef } = React;

  const [rows, setRows] = useState(() => F.PIPELINE.map(r => ({ ...r })));
  const [sortKey, setSortKey] = useState("status");
  const [sortDir, setSortDir] = useState("desc");
  // Per-column filter values (Set of allowed values, empty = all). Keys: status, module, dm, buyer
  const [filters, setFilters] = useState({});
  const [openFilter, setOpenFilter] = useState(null); // column key currently showing dropdown
  const [search, setSearch] = useState("");
  const [pageSize, setPageSize] = useState(150);

  // Apply scope (module / subteam / individuals) on top of column filters
  // Subteam scope matches the row's own `module` field (the deal's module attribution)
  // by mapping subteam id → display label, so e.g. scope.subteam="st-bscott" pulls every
  // row tagged module: "Scott" regardless of who owns it.
  const subteamLabel = useMemo(() => {
    if (!scope.subteam) return null;
    const st = F.SUBTEAMS.find(s => s.id === scope.subteam);
    return st ? st.label : null;
  }, [scope.subteam]);

  const visible = useMemo(() => {
    let out = rows;
    if (scope.module) {
      const subLabels = new Set(F.SUBTEAMS.filter(s => s.moduleId === scope.module).map(s => s.label));
      out = out.filter(r => subLabels.has(r.module));
    }
    if (scope.subteam && subteamLabel) {
      out = out.filter(r => r.module === subteamLabel);
    }
    if (scope.individuals.length) {
      out = out.filter(r => scope.individuals.includes(r.owner) || scope.individuals.includes(r.dm1) || scope.individuals.includes(r.dm2));
    }
    // Column filters
    for (const [k, set] of Object.entries(filters)) {
      if (!set || !set.size) continue;
      out = out.filter(r => {
        const v = colValue(r, k);
        if (Array.isArray(v)) return v.some(x => set.has(x));
        return set.has(v);
      });
    }
    if (search.trim()) {
      const s = search.trim().toLowerCase();
      out = out.filter(r =>
        (r.target || "").toLowerCase().includes(s) ||
        (r.buyer || "").toLowerCase().includes(s) ||
        (r.nextAction || "").toLowerCase().includes(s) ||
        (r.dm1Name || "").toLowerCase().includes(s) ||
        (r.dm2Name || "").toLowerCase().includes(s)
      );
    }
    out = [...out].sort((a, b) => {
      let av = a[sortKey], bv = b[sortKey];
      if (sortKey === "dm") { av = a.dm1Name || ""; bv = b.dm1Name || ""; }
      if (av == null) return 1;
      if (bv == null) return -1;
      if (typeof av === "number") return sortDir === "asc" ? av - bv : bv - av;
      return sortDir === "asc" ? String(av).localeCompare(String(bv)) : String(bv).localeCompare(String(av));
    });
    return out;
  }, [rows, sortKey, sortDir, scope, filters, search]);

  const update = (id, patch) => setRows(rs => rs.map(r => r.id === id ? { ...r, ...patch } : r));
  const removeRow = (id) => setRows(rs => rs.filter(r => r.id !== id));
  const addRow = () => {
    const n = rows.length + 1;
    setRows(rs => [...rs, {
      id: `T-NEW-${n}`, target: "", buyer: "—", ebitda: null, sales: null,
      status: 5.00, nextAction: "", dm1: null, dm2: null, dm1Name: null, dm2Name: null,
      owner: F.PEOPLE[0]?.id, module: "Scott", subteam: F.SUBTEAMS[0]?.id, synth: false,
    }]);
  };

  // Build option lists for each filterable column from full row set
  function colValue(r, k) {
    if (k === "status") return Number(r.status).toFixed(2);
    if (k === "module") return r.module || "—";
    if (k === "dm")     return [r.dm1Name, r.dm2Name].filter(Boolean);
    if (k === "buyer")  return r.buyer || "—";
    return r[k];
  }
  const optionsFor = useMemo(() => {
    const cache = {};
    function build(k) {
      if (cache[k]) return cache[k];
      const counts = new Map();
      for (const r of rows) {
        const v = colValue(r, k);
        if (Array.isArray(v)) v.forEach(x => counts.set(x, (counts.get(x) || 0) + 1));
        else if (v) counts.set(v, (counts.get(v) || 0) + 1);
      }
      const entries = Array.from(counts.entries());
      if (k === "status") {
        // Numeric status code — sort ascending (4.50, 5.00, … 9.00)
        entries.sort((a, b) => parseFloat(a[0]) - parseFloat(b[0]));
      } else {
        // Text columns — alphabetical
        entries.sort((a, b) => String(a[0]).localeCompare(String(b[0])));
      }
      cache[k] = entries;
      return cache[k];
    }
    return { status: build("status"), module: build("module"), dm: build("dm"), buyer: build("buyer") };
  }, [rows]);

  // Status-based stat tiles (computed against visible/filtered)
  const inRange = (r, lo, hi) => Number(r.status) >= lo && Number(r.status) <= hi;
  const eq = (r, v) => Math.abs(Number(r.status) - v) < 0.01;
  const dataWaitRe = /\b(data|diligence|dilligence|qof|q of e|info|materials|financials|cim)\b/i;
  const stats = [
    { label: "Signed LOIs",       value: visible.filter(r => eq(r, 9.0)).length, accent: true, status: "9.00" },
    { label: "Current Offers",    value: visible.filter(r => inRange(r, 8.0, 9.0)).length },
    { label: "Pending Offer",     value: visible.filter(r => inRange(r, 7.0, 7.5)).length },
    { label: "Visit",             value: visible.filter(r => eq(r, 6.0)).length, status: "6.00" },
    { label: "Conference Call",   value: visible.filter(r => eq(r, 5.5)).length, status: "5.50" },
    { label: "Waiting on Data",   value: visible.filter(r => inRange(r, 4.7, 6.0) && dataWaitRe.test(r.nextAction || "")).length },
    { label: "Leads",             value: visible.filter(r => eq(r, 5.0)).length, status: "5.00" },
    { label: "Push Needed",       value: visible.filter(r => inRange(r, 4.6, 4.7)).length },
  ];

  // Active filter chips at top
  const activeChips = [];
  for (const [k, set] of Object.entries(filters)) {
    if (!set || !set.size) continue;
    set.forEach(v => activeChips.push({ k, v }));
  }
  function clearChip(k, v) {
    setFilters(prev => {
      const next = { ...prev };
      if (next[k]) {
        const s = new Set(next[k]); s.delete(v);
        next[k] = s.size ? s : null;
      }
      return next;
    });
  }

  // Dropdown ref tracking — close on outside click
  const ddRef = useRef(null);
  useEffect(() => {
    function onDoc(e) { if (ddRef.current && !ddRef.current.contains(e.target)) setOpenFilter(null); }
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, []);

  // Reset page size when filters change
  useEffect(() => { setPageSize(150); }, [filters, search, scope]);

  const Th = ({ k, label, w, filterable, align }) => {
    const sorted = sortKey === k;
    const filtered = filters[k] && filters[k].size > 0;
    return (
      <th style={{ width: w, position: "relative" }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 4, justifyContent: align === "r" ? "flex-end" : "flex-start" }}>
          <button
            onClick={() => { if (sortKey === k) setSortDir(d => d === "asc" ? "desc" : "asc"); else { setSortKey(k); setSortDir("asc"); } }}
            style={{ background: "none", border: "none", padding: 0, cursor: "pointer", color: "inherit", font: "inherit", display: "inline-flex", alignItems: "center", gap: 3 }}>
            {label}
            {sorted && <span style={{ color: "var(--accent)", fontSize: 8 }}>{sortDir === "asc" ? "▲" : "▼"}</span>}
          </button>
          {filterable && (
            <button
              onClick={(e) => { e.stopPropagation(); setOpenFilter(of => of === k ? null : k); }}
              title={`Filter ${label}`}
              style={{
                background: filtered ? "var(--accent-soft)" : "transparent",
                border: filtered ? "1px solid var(--accent)" : "1px solid transparent",
                color: filtered ? "var(--accent-strong)" : "var(--muted)",
                borderRadius: 4, cursor: "pointer", padding: "1px 4px", fontSize: 9,
                display: "inline-flex", alignItems: "center",
              }}>
              <svg width="9" height="9" viewBox="0 0 12 12" fill="currentColor">
                <path d="M1 2h10l-4 5v3l-2 1V7L1 2z"/>
              </svg>
            </button>
          )}
        </span>
        {openFilter === k && (
          <FilterDropdown
            ref={ddRef}
            options={optionsFor[k] || []}
            selected={filters[k] || new Set()}
            onChange={(set) => setFilters(prev => ({ ...prev, [k]: set.size ? set : null }))}
            onClose={() => setOpenFilter(null)}
            label={label}
            colKey={k}
          />
        )}
      </th>
    );
  };

  return (
    <div style={{ padding: "20px 28px 60px" }}>
      {/* Stats strip — clickable to toggle status filter */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(8, 1fr)", gap: 8, marginBottom: 14 }}>
        {stats.map(s => (
          <StatTile key={s.label} label={s.label} value={s.value} accent={s.accent} compact
            active={s.status && filters.status && filters.status.has(s.status)}
            onClick={s.status ? () => {
              setFilters(prev => {
                const cur = new Set(prev.status || []);
                if (cur.has(s.status)) cur.delete(s.status); else cur.add(s.status);
                return { ...prev, status: cur.size ? cur : null };
              });
            } : null}/>
        ))}
      </div>

      {/* Search + active filter chips */}
      <div className="row" style={{ gap: 8, marginBottom: 12, alignItems: "center", flexWrap: "wrap" }}>
        <div style={{ position: "relative", minWidth: 280 }}>
          <input value={search} onChange={e => setSearch(e.target.value)}
            placeholder="Search target, buyer, DM, action…"
            style={{
              width: 280, padding: "7px 10px 7px 30px", fontSize: 12.5,
              border: "1px solid var(--line-2)", borderRadius: 6,
              background: "var(--surface)", color: "var(--ink)", outline: "none",
            }}/>
          <svg style={{ position: "absolute", left: 9, top: "50%", transform: "translateY(-50%)", color: "var(--muted)" }}
            width="12" height="12" viewBox="0 0 16 16" fill="none">
            <circle cx="7" cy="7" r="4.5" stroke="currentColor" strokeWidth="1.5"/>
            <path d="M11 11l3 3" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/>
          </svg>
        </div>
        {activeChips.map(({ k, v }, i) => (
          <button key={k + v + i} className="chip on" onClick={() => clearChip(k, v)} style={{ fontSize: 11 }}>
            <span style={{ color: "var(--muted)", marginRight: 4, textTransform: "capitalize" }}>{k === "dm" ? "DM" : k}:</span>
            {v} ✕
          </button>
        ))}
        {(activeChips.length > 0 || search) && (
          <button className="btn ghost sm" onClick={() => { setFilters({}); setSearch(""); }}>Clear all</button>
        )}
        <span style={{ flex: 1 }}/>
        <span className="muted small">
          {visible.length.toLocaleString()} {visible.length === 1 ? "deal" : "deals"}
          {visible.length > pageSize && ` · showing ${pageSize.toLocaleString()}`}
        </span>
      </div>

      <div className="card" style={{ overflow: "hidden" }}>
        <div style={{ overflowX: "auto" }}>
          <table className="dt" style={{ minWidth: 1280 }}>
            <thead><tr>
              <Th k="target" label="Target" w={260}/>
              <Th k="buyer" label="Buyer" w={220} filterable/>
              <Th k="ebitda" label="EBITDA" w={88}/>
              <Th k="sales" label="Sales" w={88}/>
              <Th k="status" label="Status" w={170} filterable/>
              <Th k="nextAction" label="Next Action"/>
              <Th k="dm" label="DMs" w={170} filterable/>
              <Th k="module" label="Module" w={110} filterable/>
              <th style={{ width: 32 }}></th>
            </tr></thead>
            <tbody>
              {visible.slice(0, pageSize).map(r => <PipelineRow key={r.id} row={r} onChange={(p) => update(r.id, p)} onRemove={() => removeRow(r.id)}/>)}
              {visible.length === 0 && <tr><td colSpan={9} className="muted" style={{ textAlign: "center", padding: 24 }}>No targets match this scope.</td></tr>}
            </tbody>
          </table>
        </div>
        {visible.length > pageSize && (
          <div style={{ padding: "10px 14px", borderTop: "1px solid var(--line-2)", display: "flex", gap: 12, alignItems: "center", justifyContent: "center" }}>
            <span className="muted small">{pageSize.toLocaleString()} of {visible.length.toLocaleString()}</span>
            <button className="btn" onClick={() => setPageSize(n => n + 150)}>Show 150 more</button>
            <button className="btn ghost sm" onClick={() => setPageSize(visible.length)}>Show all</button>
          </div>
        )}
        <div style={{ padding: "10px 14px", borderTop: "1px solid var(--line-2)" }}>
          <button className="btn" onClick={addRow}><window.Icon.plus/> Add Target</button>
        </div>
      </div>
    </div>
  );
}

// ---------------- Filter dropdown ----------------
const FilterDropdown = React.forwardRef(function FilterDropdown({ options, selected, onChange, onClose, label, colKey }, ref) {
  const F = window.VAULT_FIRM;
  const [q, setQ] = React.useState("");
  const filtered = q ? options.filter(([v]) => String(v).toLowerCase().includes(q.toLowerCase())) : options;
  function toggle(v) {
    const next = new Set(selected);
    if (next.has(v)) next.delete(v); else next.add(v);
    onChange(next);
  }
  function renderLabel(v) {
    if (colKey === "status") {
      const s = F.STATUS_BY_CODE[v];
      return s ? (
        <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
          <span className="mono" style={{ fontSize: 9.5, color: "var(--muted)" }}>{v}</span>
          <span>{s.label}</span>
        </span>
      ) : v;
    }
    return v;
  }
  return (
    <div ref={ref} style={{
      position: "absolute", top: "calc(100% + 4px)", left: 0, zIndex: 50,
      background: "var(--surface)", border: "1px solid var(--line-2)", borderRadius: 8,
      boxShadow: "0 8px 24px rgba(0,0,0,0.12)", padding: 8, width: 260,
      maxHeight: 360, display: "flex", flexDirection: "column",
    }}>
      <div className="row" style={{ alignItems: "center", justifyContent: "space-between", marginBottom: 6 }}>
        <span className="micro" style={{ color: "var(--muted)" }}>Filter by {label}</span>
        {selected.size > 0 && <button className="btn ghost sm" onClick={() => onChange(new Set())} style={{ fontSize: 10, padding: "2px 6px" }}>Clear</button>}
      </div>
      <input autoFocus value={q} onChange={e => setQ(e.target.value)} placeholder="Search…"
        style={{
          width: "100%", padding: "5px 8px", fontSize: 11.5,
          border: "1px solid var(--line-2)", borderRadius: 5,
          background: "var(--surface-2)", color: "var(--ink)", outline: "none", marginBottom: 6,
        }}/>
      <div style={{ overflowY: "auto", flex: 1 }}>
        {filtered.length === 0 && <div className="muted small" style={{ padding: 8 }}>No matches</div>}
        {filtered.slice(0, 200).map(([v, n]) => (
          <label key={v} style={{
            display: "flex", alignItems: "center", gap: 8, padding: "5px 6px", borderRadius: 4,
            cursor: "pointer", fontSize: 12,
            background: selected.has(v) ? "var(--accent-soft)" : "transparent",
          }}
          onMouseEnter={e => { if (!selected.has(v)) e.currentTarget.style.background = "var(--surface-2)"; }}
          onMouseLeave={e => { if (!selected.has(v)) e.currentTarget.style.background = "transparent"; }}>
            <input type="checkbox" checked={selected.has(v)} onChange={() => toggle(v)} style={{ accentColor: "var(--accent)" }}/>
            <span style={{ flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{renderLabel(v)}</span>
            <span className="muted small" style={{ fontSize: 10 }}>{n}</span>
          </label>
        ))}
      </div>
    </div>
  );
});

function StatTile({ label, value, accent, compact, active, onClick }) {
  const interactive = !!onClick;
  return (
    <div className="card" onClick={onClick}
      style={{
        padding: compact ? "9px 10px" : "12px 14px",
        cursor: interactive ? "pointer" : "default",
        borderColor: active ? "var(--accent)" : undefined,
        background: active ? "var(--accent-soft)" : undefined,
        transition: "background 0.12s, border-color 0.12s",
      }}>
      <div className="micro" style={{ fontSize: compact ? 9.5 : undefined, lineHeight: 1.25 }}>{label}</div>
      <div className={accent ? "display" : ""} style={{
        fontSize: compact ? 20 : 22, marginTop: compact ? 2 : 4,
        color: accent ? "var(--accent)" : "var(--ink)",
        fontWeight: accent ? undefined : 600, fontVariantNumeric: "tabular-nums",
      }}>
        {value}
      </div>
    </div>
  );
}

function PipelineRow({ row, onChange, onRemove }) {
  const F = window.VAULT_FIRM;
  const status = F.STATUS_BY_CODE[Number(row.status).toFixed(2)] || F.STATUS[0];
  const dm1 = F.PEOPLE_BY_ID[row.dm1];
  const dm2 = F.PEOPLE_BY_ID[row.dm2];
  return (
    <tr>
      <td>
        <EditableText value={row.target} onChange={(v) => onChange({ target: v })} placeholder="Target name…" bold/>
      </td>
      <td>
        <EditableText value={row.buyer} onChange={(v) => onChange({ buyer: v })} placeholder="—"/>
      </td>
      <td className="mono" style={{ fontSize: 12 }}>
        <EditableText value={row.ebitda != null ? "$" + row.ebitda + "M" : ""}
          onChange={(v) => { const n = parseFloat(String(v).replace(/[^\d.]/g,"")); onChange({ ebitda: isNaN(n) ? null : n }); }}
          placeholder="—"/>
      </td>
      <td className="mono" style={{ fontSize: 12 }}>
        <EditableText value={row.sales != null ? "$" + row.sales + "M" : ""}
          onChange={(v) => { const n = parseFloat(String(v).replace(/[^\d.]/g,"")); onChange({ sales: isNaN(n) ? null : n }); }}
          placeholder="—"/>
      </td>
      <td>
        <EditableSelect value={Number(row.status).toFixed(2)} onChange={(v) => onChange({ status: parseFloat(v) })}
          options={F.STATUS.map(s => ({ value: s.code.toFixed(2), label: `${s.code.toFixed(2)} · ${s.label}` }))}
          render={() => (
            <span className={`pill ${status.tone === "muted" ? "" : status.tone}`} style={{ background: status.tone === "muted" ? "var(--surface-2)" : undefined }}>
              <span className="dot"/>
              <span className="mono" style={{ marginRight: 4, fontSize: 9.5 }}>{Number(row.status).toFixed(2)}</span>
              {status.label}
            </span>
          )}/>
      </td>
      <td>
        <EditableText value={row.nextAction} onChange={(v) => onChange({ nextAction: v })} placeholder="—"/>
      </td>
      <td>
        <div className="row" style={{ gap: 6, alignItems: "center" }}>
          <div style={{ display: "flex", gap: 2 }}>
            {dm1 && <window.Avatar id={dm1.id} size={20}/>}
            {dm2 && <window.Avatar id={dm2.id} size={20}/>}
            {!dm1 && !dm2 && (row.dm1Name || row.dm2Name) && (
              <span style={{ width: 20, height: 20, borderRadius: "50%", background: "var(--surface-2)", display: "inline-flex", alignItems: "center", justifyContent: "center", fontSize: 9, color: "var(--muted)" }}>?</span>
            )}
          </div>
          <div style={{ display: "flex", flexDirection: "column", lineHeight: 1.15, minWidth: 0 }}>
            {row.dm1Name && <span style={{ fontSize: 11, fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{row.dm1Name}</span>}
            {row.dm2Name && <span className="muted" style={{ fontSize: 10.5, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{row.dm2Name}</span>}
            {!row.dm1Name && !row.dm2Name && <span className="muted small">—</span>}
          </div>
        </div>
      </td>
      <td>
        <span className="pill" style={{ background: "var(--surface-2)", fontSize: 10.5 }}>{row.module || "—"}</span>
      </td>
      <td className="r">
        <button className="btn ghost sm" onClick={onRemove} title="Remove" style={{ color: "var(--muted)", padding: 4 }}>
          <svg width="13" height="13" viewBox="0 0 16 16" fill="none"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>
        </button>
      </td>
    </tr>
  );
}

function EditableText({ value, onChange, placeholder, bold }) {
  const [editing, setEditing] = React.useState(false);
  const [v, setV] = React.useState(value);
  React.useEffect(() => setV(value), [value]);
  if (editing) {
    return (
      <input autoFocus value={v} onChange={e => setV(e.target.value)}
        onBlur={() => { setEditing(false); onChange(v); }}
        onKeyDown={(e) => { if (e.key === "Enter") { setEditing(false); onChange(v); } if (e.key === "Escape") { setEditing(false); setV(value); } }}
        style={{
          width: "100%", padding: "5px 7px", fontSize: 12.5,
          border: "1px solid var(--accent)", borderRadius: 5,
          background: "var(--surface)", color: "var(--ink)", outline: "none",
          boxShadow: "0 0 0 3px var(--accent-soft)",
        }}/>
    );
  }
  return (
    <span onClick={() => setEditing(true)} style={{ cursor: "text", display: "inline-block", padding: "2px 4px", borderRadius: 4, minWidth: 60, fontWeight: bold ? 600 : undefined }}>
      {value || <span className="muted">{placeholder}</span>}
    </span>
  );
}

function EditableSelect({ value, onChange, options, render }) {
  const [editing, setEditing] = React.useState(false);
  if (editing) {
    return (
      <select autoFocus value={value} onChange={e => { onChange(e.target.value); setEditing(false); }}
        onBlur={() => setEditing(false)}
        style={{
          padding: "4px 6px", fontSize: 12.5,
          border: "1px solid var(--accent)", borderRadius: 5,
          background: "var(--surface)", color: "var(--ink)", outline: "none",
          boxShadow: "0 0 0 3px var(--accent-soft)",
        }}>
        {options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
      </select>
    );
  }
  return (
    <span onClick={() => setEditing(true)} style={{ cursor: "pointer", display: "inline-block" }}>
      {render(value)}
    </span>
  );
}

window.PipelineScreen = PipelineScreen;
