/* events.jsx — Signal Events tab.
   Full feed of all parsed events, with channel-category filter and analyst filter.
   Click any row → flyout with parser internals.
*/

function ChannelDot({ cat }) {
  const color = cat === "signals" ? "var(--accent)" :
                cat === "analysis" ? "var(--c-watch)" :
                cat === "chat" ? "var(--fg-3)" : "var(--fg-3)";
  return <span className="dot" style={{ color, background: color, width: 6, height: 6, marginRight: 8 }} />;
}

function CategoryFilter({ value, onChange }) {
  const opts = [
    { v: "all", label: "All" },
    { v: "signals", label: "Signals" },
    { v: "analysis", label: "Analysis" },
    { v: "chat", label: "Chat" },
  ];
  return (
    <div style={{ display: "flex", gap: 0, border: "1px solid var(--border-1)", borderRadius: "var(--radius)", overflow: "hidden" }}>
      {opts.map(o => (
        <button key={o.v} className="btn" style={{
          border: 0, borderRadius: 0,
          background: value === o.v ? "var(--bg-3)" : "var(--bg-1)",
          color: value === o.v ? "var(--accent)" : "var(--fg-1)",
          padding: "10px 16px", fontSize: 12,
          letterSpacing: ".06em", fontFamily: "var(--f-mono)",
          textTransform: "uppercase",
        }} onClick={() => onChange(o.v)}>{o.label}</button>
      ))}
    </div>
  );
}

function SignalEvents({ events, analysts, onClickEvent, onDelete, onDeleteMany }) {
  const [cat, setCat] = useState("all");
  const [action, setAction] = useState("all");
  const [inst, setInst] = useState("all");
  const [filter, setFilter] = useState("");
  const [selected, setSelected] = useState(() => new Set());
  const selectable = !!onDeleteMany;

  const filtered = useMemo(() => {
    const fl = filter.toLowerCase().trim();
    return events.filter(e => {
      if (cat !== "all" && e.channelCategory !== cat) return false;
      if (action !== "all" && e.action !== action) return false;
      if (!matchesInstrument(e, inst)) return false;
      if (!fl) return true;
      return e.ticker.toLowerCase().includes(fl) || e.analyst.toLowerCase().includes(fl) || e.raw.toLowerCase().includes(fl);
    });
  }, [events, cat, action, inst, filter]);

  const actionOpts = ["all", "open", "add", "trim", "cut", "close", "hold", "watch", "expire"];

  // ── Multi-select ──
  const filteredIds = filtered.map(e => e.id);
  const allSelected = selectable && filteredIds.length > 0 && filteredIds.every(id => selected.has(id));
  function toggle(id) {
    setSelected(prev => { const n = new Set(prev); n.has(id) ? n.delete(id) : n.add(id); return n; });
  }
  function toggleAll() {
    setSelected(prev => {
      const n = new Set(prev);
      if (allSelected) filteredIds.forEach(id => n.delete(id)); else filteredIds.forEach(id => n.add(id));
      return n;
    });
  }
  async function bulkDelete() {
    const ids = [...selected];
    if (!ids.length) return;
    if (await confirmDialog({ title: "Delete events", message: `Delete ${ids.length} selected event${ids.length === 1 ? "" : "s"}? They'll be removed from positions, recaps and charts too.`, confirmLabel: `Delete ${ids.length}`, danger: true })) {
      onDeleteMany(ids);
      setSelected(new Set());
    }
  }
  const colCount = 9 + (selectable ? 1 : 0);

  return (
    <div>
      <div className="filterbar" style={{ gridTemplateColumns: "1fr auto auto auto" }}>
        <input className="input search" placeholder="Filter by ticker, analyst, or text…" value={filter} onChange={e => setFilter(e.target.value)} />
        <InstrumentFilter value={inst} onChange={setInst} />
        <CategoryFilter value={cat} onChange={setCat} />
        <select className="select" value={action} onChange={e => setAction(e.target.value)} style={{ fontFamily: "var(--f-mono)", fontSize: 12, textTransform: "uppercase", letterSpacing: ".06em" }}>
          {actionOpts.map(a => <option key={a} value={a}>{a}</option>)}
        </select>
      </div>

      {selectable && selected.size > 0 && (
        <div className="bulk-bar">
          <span><strong>{selected.size}</strong> selected</span>
          <span style={{ flex: 1 }} />
          <button className="btn" onClick={() => setSelected(new Set())}>Clear</button>
          <button className="btn danger" onClick={bulkDelete}>{I("trash", { size: 14 })} Delete {selected.size}</button>
        </div>
      )}

      <div className="panel">
        <div className="panel-hdr">
          <div className="panel-title">Signal Events feed</div>
          <div className="panel-meta">{filtered.length} of {events.length} · live</div>
        </div>
        <div className="scroll-y" style={{ maxHeight: "calc(100vh - 250px)", minHeight: 400 }}>
          <table className="tbl tbl-fixed">
            <colgroup>
              {selectable && <col style={{ width: "3%" }} />}
              <col style={{ width: "11%" }} />
              <col style={{ width: "12%" }} />
              <col style={{ width: "7%" }} />
              <col style={{ width: "14%" }} />
              <col style={{ width: "8%" }} />
              <col style={{ width: "7%" }} />
              <col style={{ width: "13%" }} />
              <col style={{ width: "24%" }} />
              <col style={{ width: "4%" }} />
            </colgroup>
            <thead>
              <tr>
                {selectable && <th style={{ textAlign: "center" }}><input type="checkbox" checked={allSelected} onChange={toggleAll} title="Select all" /></th>}
                <th>Time</th>
                <th>Analyst</th>
                <th>Ticker</th>
                <th>Instrument</th>
                <th>Action</th>
                <th>Conf</th>
                <th>Channel</th>
                <th>Raw note</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {filtered.map(e => (
                <tr key={e.id} onClick={() => onClickEvent(e)} style={{ cursor: "pointer" }} className={cx(selected.has(e.id) && "row-selected")}>
                  {selectable && (
                    <td style={{ textAlign: "center" }} onClick={(ev) => ev.stopPropagation()}>
                      <input type="checkbox" checked={selected.has(e.id)} onChange={() => toggle(e.id)} />
                    </td>
                  )}
                  <td className="muted mono">{fmtTime(e.ts, {short:true})}</td>
                  <td><AnalystChip analyst={e.analyst} analysts={analysts} /></td>
                  <td><span className="ticker">${e.ticker}</span></td>
                  <td><InstrumentCell event={e} /></td>
                  <td><ActionPill kind={e.action} /></td>
                  <td><ConfPill level={e.confidence} /></td>
                  <td className="muted mono" style={{ fontSize: 11, whiteSpace: "nowrap" }}><ChannelDot cat={e.channelCategory} />{e.channel}</td>
                  <td className="muted" style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{e.raw}</td>
                  <td style={{ textAlign: "right" }}>
                    {onDelete && (
                      <button
                        className="icon-btn danger"
                        title="Delete event"
                        onClick={async (ev) => { ev.stopPropagation(); if (await confirmDialog({ title: "Delete event", message: `Delete this ${e.action.toUpperCase()} $${e.ticker} event? It will also be removed from positions, recaps and charts.`, confirmLabel: "Delete", danger: true })) onDelete(e.id); }}
                      >{I("trash", { size: 14 })}</button>
                    )}
                  </td>
                </tr>
              ))}
              {filtered.length === 0 && <tr><td colSpan={colCount}><Empty msg="No events match." /></td></tr>}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

// ─── Flyout: full parser internals for a single event
function EventFlyout({ event, onClose, onDelete }) {
  if (!event) return null;
  useEffect(() => {
    const handler = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, []);
  return [
    <div key="back" className="flyout-back" onClick={onClose} />,
    <div key="flyout" className="flyout" role="dialog" aria-modal="true">
      <div className="flyout-hdr">
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
              <span className="ticker" style={{ fontSize: 18 }}>${event.ticker}</span>
              <ActionPill kind={event.action} />
              <ConfPill level={event.confidence} />
            </div>
            <div className="mono" style={{ fontSize: 11, color: "var(--fg-2)", marginTop: 4 }}>
              {event.analyst} · {fmtTime(event.ts)}
            </div>
          </div>
          <div style={{ display: "flex", gap: 6 }}>
            {onDelete && (
              <button
                className="icon-btn danger"
                title="Delete event"
                onClick={async () => { if (await confirmDialog({ title: "Delete event", message: `Delete this ${event.action.toUpperCase()} $${event.ticker} event? It will also be removed from positions, recaps and charts.`, confirmLabel: "Delete", danger: true })) onDelete(event.id); }}
              >{I("trash", { size: 16 })}</button>
            )}
            <button className="btn" onClick={onClose} style={{ padding: 6 }}>{I("close", { size: 16 })}</button>
          </div>
        </div>
        <div className="flyout-body">
          <div className="field">
            <h5>Raw message</h5>
            <div className="raw-msg" style={{ background: "var(--bg-2)", border: "1px solid var(--border-1)", borderRadius: 6, padding: "12px 14px" }}>{event.raw}</div>
          </div>
          <div className="field">
            <h5>Source</h5>
            <div className="mono" style={{ fontSize: 12 }}>
              <ChannelDot cat={event.channelCategory} />{event.channel}
              <span style={{ color: "var(--fg-3)", margin: "0 8px" }}>·</span>
              <span style={{ color: "var(--fg-2)" }}>category</span> <strong style={{ color: "var(--fg-0)" }}>{event.channelCategory}</strong>
              <span style={{ color: "var(--fg-3)", margin: "0 8px" }}>·</span>
              <span style={{ color: "var(--fg-2)" }}>id</span> <span style={{ color: "var(--fg-1)" }}>{event.messageId}</span>
            </div>
          </div>
          <div className="field">
            <h5>Extracted event</h5>
            <pre style={{ background: "var(--bg-0)", border: "1px solid var(--border-1)", borderRadius: 6, padding: "12px 14px", fontFamily: "var(--f-mono)", fontSize: 12, color: "var(--fg-mono)", margin: 0, lineHeight: 1.6 }}>
{`{
  "ticker":      "${event.ticker}",
  "instrument":  "${isOption(event) ? "option" : "shares"}",
  "action":      "${event.action}",
  "direction":   "${event.direction}",
  "contract":    ${event.contract ? `"${event.contract}"` : "null"},
  "strike":      ${event.strike == null ? "null" : event.strike},
  "expiry":      ${event.expiry ? `"${event.expiry}"` : "null"},
  "option_type": ${event.optionType ? `"${event.optionType}"` : "null"},
  "price":         ${event.price == null ? "null" : event.price.toFixed(2)},
  "current_price": ${event.currentPrice == null ? "null" : event.currentPrice},
  "confidence":    "${event.confidence}",
  "raw_note":    "${event.raw.replace(/"/g, '\\"')}"
}`}
            </pre>
          </div>
          <div className="field">
            <h5>Parser reasoning</h5>
            <div style={{ fontSize: 12, color: "var(--fg-1)", lineHeight: 1.6 }}>
              {event.reasoning.summary.split(/("[^"]+")/).map((part, i) =>
                part.startsWith('"') ? <span key={i} style={{ background: "var(--accent-glow)", color: "var(--accent)", padding: "1px 4px", borderRadius: 2 }}>{part}</span> : <span key={i}>{part}</span>
              )}
            </div>
          </div>
          <div className="field">
            <h5>Pipeline</h5>
            <div style={{ display: "grid", gridTemplateColumns: "1fr", gap: 6, fontFamily: "var(--f-mono)", fontSize: 11 }}>
              <div style={{ display: "grid", gridTemplateColumns: "120px 1fr", gap: 8 }}>
                <span style={{ color: "var(--fg-2)" }}>scraper</span>
                <span style={{ color: "var(--fg-0)" }}>discord.py-self · {event.channel}</span>
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "120px 1fr", gap: 8 }}>
                <span style={{ color: "var(--fg-2)" }}>parser</span>
                <span style={{ color: "var(--fg-0)" }}>claude-haiku-4-5 · 220ms</span>
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "120px 1fr", gap: 8 }}>
                <span style={{ color: "var(--fg-2)" }}>storage</span>
                <span style={{ color: "var(--fg-0)" }}>trade_events · row {event.id}</span>
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "120px 1fr", gap: 8 }}>
                <span style={{ color: "var(--fg-2)" }}>aggregator</span>
                <span style={{ color: "var(--fg-0)" }}>positions[{event.analyst}|{event.ticker}|{event.contract || "shares"}]</span>
              </div>
            </div>
          </div>
        </div>
      </div>
  ];
}

Object.assign(window, { SignalEvents, EventFlyout, ChannelDot });
