const { useState, useEffect } = React;

/* CRM · Signals — change-event inbox. Defaults to the TERRITORY feed
 * (crm_territory_feed: all recent events across your metros, populated out of
 * the box) with a "My watchlist" toggle (crm_signal_feed: only watched
 * buildings / saved orgs). Type / metro / status are independent filters.
 * Create-deal works from either: inbox rows → crm_convert_signal_to_deal;
 * territory rows → crm_create_deal from the event. Real data only. */

const EVT_MAP = {
  new_mortgage:  { t: "mortgage", label: "New mortgage",  bg: "var(--green-bg)",  c: "var(--green)",          prov: "var(--src-government)" },
  deed_transfer: { t: "deed",     label: "Deed transfer", bg: "#47556914",        c: "var(--src-government)", prov: "var(--src-government)" },
  ucc_lien:      { t: "ucc",      label: "UCC lien",      bg: "#7c3aed14",        c: "var(--src-hedge)",      prov: "var(--src-government)" },
  warn_layoff:   { t: "warn",     label: "WARN layoff",   bg: "var(--red-bg)",    c: "var(--red)",            prov: "var(--src-fed)" },
  form_d_raise:  { t: "formd",    label: "Form D",        bg: "var(--accent-bg)", c: "var(--accent)",         prov: "var(--accent)" },
};
const prettyBBL = (ref) => (ref && ref.indexOf("BBL:") === 0) ? "BBL " + ref.slice(4) : (ref || "");
const fmtMoney = (n) => { n = Number(n) || 0; return n >= 1e6 ? "$" + (n / 1e6).toFixed(1) + "M" : n >= 1e3 ? "$" + n.toLocaleString() : "$" + n; };
// Per-event detail pulled from aiciq_events.payload (more context than the title line).
function eventContext(type, p) {
  if (!p || typeof p !== "object") return null;
  if (type === "new_mortgage" || type === "deed_transfer") return p.address ? "📍 " + p.address : null;
  if (type === "ucc_lien") return [p.debtor && "Debtor: " + p.debtor, p.collateral && "Collateral: " + String(p.collateral).slice(0, 90)].filter(Boolean).join("  ·  ") || null;
  if (type === "form_d_raise") return [p.entity, p.amount_sold != null && "sold " + fmtMoney(p.amount_sold), p.cik && "CIK " + p.cik].filter(Boolean).join("  ·  ") || null;
  if (type === "warn_layoff") return [p.employees != null && p.employees + " roles", p.site, p.city].filter(Boolean).join("  ·  ") || null;
  return null;
}
function baseRow(r, status, inboxId, dealId) {
  const m = EVT_MAP[r.event_type] || { t: r.event_type, label: r.event_type, bg: "var(--bg-3)", c: "var(--fg-2)", prov: "var(--fg-3)" };
  return {
    id: (inboxId != null ? "inbox-" + inboxId : "evt-" + r.event_id), inboxId, eventId: r.event_id, t: m.t,
    metro: (r.state || "").toLowerCase(), status: status || "new", chip: { label: m.label, bg: m.bg, c: m.c },
    when: r.event_date || "", a: prettyBBL(r.parcel_ref) || r.counterparty || "—",
    bbl: r.parcel_ref ? prettyBBL(r.parcel_ref) : (r.state || ""), fact: r.title, parcel_ref: r.parcel_ref,
    amount: r.amount, prov: { label: "via " + (r.source || "—"), dot: m.prov }, asOf: r.event_date || "",
    convertedTo: dealId ? "Deal #" + dealId : null,
    ctx: eventContext(r.event_type, r.payload), srcUrl: r.source_url || null,
  };
}
const mapInbox = (r) => baseRow(r, r.status, r.inbox_id, r.deal_id);
const mapTerritory = (r) => baseRow(r, "new", null, null);

const TYPE_KEYS = [["all", "All"], ["mortgage", "New mortgage"], ["deed", "Deed transfer"], ["ucc", "UCC lien"], ["warn", "WARN layoff"], ["formd", "Form D"]];
const TYPE_TO_EVENTS = { mortgage: ["new_mortgage"], deed: ["deed_transfer"], ucc: ["ucc_lien"], warn: ["warn_layoff"], formd: ["form_d_raise"] };
const STATUS_KEYS = [["all", "All"], ["new", "New"], ["converted", "Converted"], ["dismissed", "Dismissed"]];
const METROS = ["all", "ny", "ct", "nj", "fl"];
const SINCE_OPTS = [["all", "All time", null], ["7", "7d", 7], ["30", "30d", 30], ["90", "90d", 90], ["365", "1y", 365]];
const sinceDate = (days) => days ? new Date(Date.now() - days * 864e5).toISOString().slice(0, 10) : null;

function SignalsInbox() {
  const { toast, persona } = React.useContext(window.CrmContext);
  const Ico = window.CrmIco;
  const [mode, setMode] = useState("territory");   // territory | watchlist
  const [events, setEvents] = useState([]);
  const [hidden, setHidden] = useState({});         // local dismiss for territory rows
  const [loaded, setLoaded] = useState(false);
  const [err, setErr] = useState(null);
  const [f, setF] = useState({ type: "all", metro: "all", status: "all" });
  const [since, setSince] = useState("all");        // SINCE_OPTS key
  const [retry, setRetry] = useState(0);

  useEffect(() => {
    const c = window.ContactIQ && window.ContactIQ.client;
    if (!c) { setLoaded(true); return; }
    let alive = true; setLoaded(false); setErr(null);
    const loadedRef = { done: false };
    const finish = (e) => { if (!alive || loadedRef.done) return; loadedRef.done = true; clearTimeout(watchdog); if (e) setErr(e); setLoaded(true); };
    // Watchdog: if the feed RPC stalls, never leave the page stuck on
    // "Loading…" — surface a retryable error instead of hanging forever.
    const watchdog = setTimeout(() => finish("Signals took too long to load — the territory feed may be busy."), 12000);
    const days = (SINCE_OPTS.find((o) => o[0] === since) || [])[2] || null;
    const call = mode === "territory"
      ? c.rpc("crm_territory_feed", { p_metros: null, p_limit: 200, p_types: f.type === "all" ? null : (TYPE_TO_EVENTS[f.type] || null), p_since: sinceDate(days) }).then(({ data, error }) => { if (error) { finish(error.message || "Could not load signals."); return; } if (alive && data) setEvents(data.map(mapTerritory)); finish(null); })
      : c.rpc("crm_signal_feed", { p_status: null, p_limit: 200 }).then(({ data, error }) => { if (error) { finish(error.message || "Could not load signals."); return; } if (alive && data) setEvents(data.map(mapInbox)); finish(null); });
    call.catch((e) => finish((e && e.message) || "Could not load signals."));
    return () => { alive = false; clearTimeout(watchdog); };
  }, [mode, f.type, since, retry]);

  const visible = events.filter((e) => !hidden[e.id]
    && (f.type === "all" || e.t === f.type) && (f.metro === "all" || e.metro === f.metro) && (f.status === "all" || e.status === f.status));

  const createDeal = (e) => {
    const c = window.ContactIQ && window.ContactIQ.client;
    if (c) {
      if (e.inboxId != null) c.rpc("crm_convert_signal_to_deal", { p_inbox_id: e.inboxId }).catch(() => {});
      else c.rpc("crm_create_deal", { p_title: e.a + " — " + e.chip.label, p_deal_type: persona === "lender" ? "loan" : "lease", p_parcel_ref: e.parcel_ref, p_value_usd: e.amount || null }).catch(() => {});
    }
    toast("Deal created from " + e.chip.label.toLowerCase() + " signal");
  };
  const dismiss = (e) => {
    const c = window.ContactIQ && window.ContactIQ.client;
    if (e.inboxId != null && c) c.rpc("crm_signal_dismiss", { p_inbox_id: e.inboxId }).catch(() => {});
    setHidden((h) => ({ ...h, [e.id]: true }));
    toast("Signal dismissed");
  };

  const chip = (active, label, cnt, onClick) => (
    <button className={"fchip" + (active ? " on" : "")} onClick={onClick}>{label}{cnt != null && <span className="fc-cnt"> {cnt}</span>}</button>
  );

  return (
    <div className="page">
      <div className="page-head" style={{ marginBottom: "16px" }}>
        <div className="ph-text">
          <div className="eyebrow">Change-event inbox</div>
          <h1 className="page-title">Signals</h1>
          <div className="page-sub">{mode === "territory" ? "All recent change-events across your territory — convert any to a deal" : "Events on your watched buildings & saved accounts"}</div>
        </div>
        <div className="persona-seg" title="Feed scope">
          <button className={mode === "territory" ? "on" : ""} onClick={() => setMode("territory")}>Territory</button>
          <button className={mode === "watchlist" ? "on" : ""} onClick={() => setMode("watchlist")}>My watchlist</button>
        </div>
      </div>

      <div className="filter-bar">
        <span className="eyebrow" style={{ marginRight: "2px" }}>Type</span>
        {TYPE_KEYS.map(([k, l]) => <span key={k}>{chip(f.type === k, l, k === "all" ? events.length : events.filter((e) => e.t === k).length, () => setF((s) => ({ ...s, type: k })))}</span>)}
      </div>
      <div className="filter-bar">
        <span className="eyebrow" style={{ marginRight: "2px" }}>Metro</span>
        {METROS.map((m) => <span key={m}>{chip(f.metro === m, m === "all" ? "All" : m.toUpperCase(), null, () => setF((s) => ({ ...s, metro: m })))}</span>)}
        {mode === "territory" && <><span className="filter-sep"></span><span className="eyebrow" style={{ marginRight: "2px" }}>Since</span>
        {SINCE_OPTS.map(([k, l]) => <span key={k}>{chip(since === k, l, null, () => setSince(k))}</span>)}</>}
        {mode === "watchlist" && <><span className="filter-sep"></span><span className="eyebrow" style={{ marginRight: "2px" }}>Status</span>
        {STATUS_KEYS.map(([k, l]) => <span key={k}>{chip(f.status === k, l, k === "all" ? events.length : events.filter((e) => e.status === k).length, () => setF((s) => ({ ...s, status: k })))}</span>)}</>}
      </div>

      <div className="inbox">
        {visible.map((e) => (
          <div className={"sig-row" + (e.status === "dismissed" ? " converted" : "")} key={e.id}>
            <div className="sig-col-type">
              <span className="evt-chip" style={{ background: e.chip.bg, color: e.chip.c }}><span className="ed"></span>{e.chip.label}</span>
              <span className="sig-when">{e.when}</span>
            </div>
            <div className="sig-col-main">
              <div className="sr-addr"><span className="a">{e.a}</span><span className="bbl">{e.bbl}</span></div>
              <div className="sr-fact">{e.fact}</div>
              {e.ctx && <div className="sr-fact" style={{ color: "var(--fg-2)", fontSize: "var(--fs-base)", marginTop: "2px" }}>{e.ctx}</div>}
            </div>
            <div className="sig-col-prov">
              {e.srcUrl
                ? <a className="src chip" href={e.srcUrl} target="_blank" rel="noopener" title="Open source document"><span className="sdot" style={{ background: e.prov.dot }}></span>{e.prov.label} ↗</a>
                : <span className="src chip"><span className="sdot" style={{ background: e.prov.dot }}></span>{e.prov.label}</span>}
              <span className="src"><span className="sdot" style={{ background: "var(--fg-3)" }}></span>as-of {e.asOf}</span>
            </div>
            <div className="sig-col-action">
              {e.status === "converted"
                ? <a className="converted-link" onClick={() => toast("Opening deal")}>{e.convertedTo || "View deal"} <Ico.Arrow/></a>
                : <>
                    <button className="btn btn-primary btn-sm" onClick={() => createDeal(e)}><Ico.Plus s={12}/>Create deal</button>
                    <button className="row-action" style={{ background: "none", border: 0, color: "var(--fg-3)", cursor: "pointer" }} onClick={() => dismiss(e)}>Dismiss</button>
                  </>}
            </div>
          </div>
        ))}
        {!visible.length && (
          <div className="muted" style={{ padding: "28px", textAlign: "center", fontSize: "var(--fs-base)" }}>
            {!loaded ? "Loading…"
              : err ? <span>{err} <button className="btn btn-sm" style={{ marginLeft: "8px" }} onClick={() => setRetry((n) => n + 1)}>Retry</button></span>
              : mode === "watchlist" ? "Nothing in your watchlist yet — switch to Territory, or watch buildings / save accounts."
              : "No events match these filters."}
          </div>
        )}
      </div>

      <div style={{ marginTop: "14px", display: "flex", alignItems: "center", justifyContent: "center" }}>
        <span className="muted" style={{ fontSize: "var(--fs-sm)" }}>Showing {visible.length} of {events.length} events · {mode === "territory" ? "territory feed" : "watchlist"}</span>
      </div>
    </div>
  );
}

function CrmSignalsPage({ go, user }) {
  return <window.CrmShell go={go} user={user} current="signals"><SignalsInbox/></window.CrmShell>;
}
window.CrmSignalsPage = CrmSignalsPage;
