// Mainstay tracking table — server-side filters, pagination, stats from API
const { useState: useTS, useEffect: useTE, useRef: useTR } = React;

const PAGE_SIZE = 24;

// Map a raw API lead row → component's internal shape.
function normalizeLead(l) {
  const fullName = [l.lead_first_name, l.lead_last_name].filter(Boolean).join(" ");
  const typeMap  = { buy: "Buy", buying: "Buy", sell: "Sell", selling: "Sell", lease: "Lease", leasing: "Lease" };
  const pqMap    = { yes: "Yes", no: "No", not_sure: "Not sure" };
  const agent    = l.assigned_agent_name ? {
    name:     l.assigned_agent_name,
    initials: l.assigned_agent_name.split(" ").map((w) => w[0] || "").join("").slice(0, 2).toUpperCase(),
    office:   null,
  } : null;
  return {
    id:          l.id,
    lead_id:     l.lead_id,
    uuid:        l.uuid,
    name:        fullName || "Unknown",
    phone:       l.lead_phone  || "",
    email:       l.lead_email  || "",
    street:      l.street_address || "",
    city:        l.city        || "",
    state:       l.state       || "",
    zip:         l.zipcode     || "",
    types:       l.lead_type ? [typeMap[(l.lead_type || "").toLowerCase()] || l.lead_type] : [],
    preQual:     pqMap[(l.pre_qualified || "").toLowerCase()] || l.pre_qualified || "",
    status:      l.status      || "",
    lead_status: l.lead_status || "",
    agent,
    created:     l.received_at || "",
    note_count:  l.note_count  || 0,
    history:     [],
    comments:    [],
    timeline:    l.timeline            || "",
    bestTime:    l.best_time_to_call   || "",
    cashOffer:   l.cash_offer          || false,
    listingDate: l.desired_listing_date || "",
    notes:       l.background_info     || "",
  };
}

function TrackingTable({ refreshKey, onOpen, density, meta, onToast }) {
  // ── Data state ──────────────────────────────────────────────────────────────
  const [leads,       setLeads]       = useTS([]);
  const [loading,     setLoading]     = useTS(false);
  const [totalCount,  setTotalCount]  = useTS(0);
  const [hasNext,     setHasNext]     = useTS(false);
  const [hasPrev,     setHasPrev]     = useTS(false);
  const [stats,       setStats]       = useTS({ total: 0, unassigned: 0, active: 0, closed: 0 });
  const [page,        setPage]        = useTS(1);
  const [exportBusy,  setExportBusy]  = useTS(false);

  // ── Filter UI state ─────────────────────────────────────────────────────────
  const [q,          setQ]          = useTS("");
  const [status,     setStatus]     = useTS("");
  const [leadStatus, setLeadStatus] = useTS("");
  const [days,       setDays]       = useTS("");
  const [agentOpt,   setAgentOpt]   = useTS({ value: "", label: "" });
  const [stateOpt,   setStateOpt]   = useTS({ value: "", label: "" });

  // Ref holding current filter values for async/setTimeout callbacks (avoids stale closures)
  const F = useTR({ search: "", status: "", lead_status: "", days: "", agent: "", state: "", page: 1 });
  const searchTimer = useTR(null);

  const compact    = density === "compact";
  const rowPad     = compact ? "11px 16px" : "16px";
  const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE));
  const hasFilters = !!(q || status || leadStatus || days || agentOpt.value || stateOpt.value);

  // ── Loaders ─────────────────────────────────────────────────────────────────

  async function doLoadStats() {
    try {
      const data = await window.api.getStats();
      if (data) setStats(data);
    } catch (_) {}
  }

  async function doLoadLeads(params) {
    setLoading(true);
    try {
      const data = await window.api.getLeads(params);
      if (data) {
        setLeads((data.results || []).map(normalizeLead));
        setTotalCount(data.count || 0);
        setHasNext(!!data.next);
        setHasPrev(!!data.previous);
      }
    } catch (_) {} finally {
      setLoading(false);
    }
  }

  // Initial load + re-load on refreshKey change (e.g. after form submit)
  useTE(() => {
    const p = { ...F.current, page: 1, "page-size": PAGE_SIZE };
    F.current = { ...F.current, page: 1 };
    setPage(1);
    doLoadLeads(p);
    doLoadStats();
  }, [refreshKey]);

  // ── Filter change handlers ───────────────────────────────────────────────────

  function chStatus(v) {
    setStatus(v); F.current.status = v; F.current.page = 1; setPage(1);
    doLoadLeads({ ...F.current, "page-size": PAGE_SIZE });
  }
  function chLeadStatus(v) {
    setLeadStatus(v); F.current.lead_status = v; F.current.page = 1; setPage(1);
    doLoadLeads({ ...F.current, "page-size": PAGE_SIZE });
  }
  function chDays(v) {
    setDays(v); F.current.days = v; F.current.page = 1; setPage(1);
    doLoadLeads({ ...F.current, "page-size": PAGE_SIZE });
  }
  function chAgent(opt) {
    setAgentOpt(opt); F.current.agent = opt.value; F.current.page = 1; setPage(1);
    doLoadLeads({ ...F.current, "page-size": PAGE_SIZE });
  }
  function chState(opt) {
    setStateOpt(opt); F.current.state = opt.value; F.current.page = 1; setPage(1);
    doLoadLeads({ ...F.current, "page-size": PAGE_SIZE });
  }
  function chSearch(v) {
    setQ(v); F.current.search = v;
    clearTimeout(searchTimer.current);
    searchTimer.current = setTimeout(() => {
      F.current.page = 1; setPage(1);
      doLoadLeads({ ...F.current, "page-size": PAGE_SIZE });
    }, 300);
  }
  function gotoPage(n) {
    if (n < 1) return;
    if (n > page && !hasNext) return;
    if (n < page && !hasPrev) return;
    setPage(n); F.current.page = n;
    doLoadLeads({ ...F.current, "page-size": PAGE_SIZE });
  }
  async function doExport() {
    setExportBusy(true);
    const { search, status, lead_status, days, agent, state } = F.current;
    try {
      const r = await window.api.exportLeads({ search, status, lead_status, days, agent, state });
      if (r?.status === "success") {
        onToast && onToast("Export queued", "You'll receive an email with the Excel file shortly.");
      } else {
        const msg = typeof r?.data === "string" ? r.data : (r?.data?.detail || r?.message || "Export failed.");
        onToast && onToast("Export failed", msg);
      }
    } catch (_) {
      onToast && onToast("Export failed", "Something went wrong. Please try again.");
    } finally {
      setTimeout(() => setExportBusy(false), 3000);
    }
  }

  function resetFilters() {
    setQ(""); setStatus(""); setLeadStatus(""); setDays("");
    setAgentOpt({ value: "", label: "" }); setStateOpt({ value: "", label: "" });
    setPage(1); setHasNext(false); setHasPrev(false);
    F.current = { search: "", status: "", lead_status: "", days: "", agent: "", state: "", page: 1 };
    doLoadLeads({ ...F.current, "page-size": PAGE_SIZE });
    doLoadStats();
  }

  // ── Dropdown option lists ────────────────────────────────────────────────────

  const statusOptions = [
    { value: "", label: "All statuses" },
    ...(meta?.inbound_status || []).map((s) => ({ value: s.id, label: s.identity })),
  ];
  const leadStatusOptions = meta?.lead_status ? [
    { value: "", label: "All lead statuses" },
    ...meta.lead_status.map((s) => ({ value: s.id, label: s.identity })),
  ] : null;
  const dayOptions = [
    { value: "",   label: "All time"      },
    { value: "7",  label: "Last 7 days"   },
    { value: "30", label: "Last 30 days"  },
    { value: "90", label: "Last 90 days"  },
  ];

  // ── Render ───────────────────────────────────────────────────────────────────

  return (
    <div style={{ maxWidth: 1240, margin: "0 auto", padding: "30px 28px 80px" }}>
      {/* heading + stats */}
      <div className="fade-up" style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 20, flexWrap: "wrap", marginBottom: 20 }}>
        <div>
          <h1 style={{ fontSize: 27, fontWeight: 800, margin: "0 0 6px", color: "var(--navy)", letterSpacing: "-.02em" }}>My leads</h1>
          <p style={{ margin: 0, color: "var(--desc)", fontSize: 14.5 }}>Every lead Mainstay has submitted, with live agent and status from the pipeline.</p>
        </div>
        <div style={{ display: "flex", gap: 10 }}>
          <Stat label="Total"      value={stats.total}      tone="navy"    />
          <Stat label="Unassigned" value={stats.unassigned} tone="neutral" />
          <Stat label="Active"     value={stats.active}     tone="blue"    />
          <Stat label="Closed"     value={stats.closed}     tone="emerald" />
        </div>
      </div>

      {/* filter bar */}
      <div className="fade-up" style={{ animationDelay: ".04s", display: "flex", gap: 10, flexWrap: "wrap", alignItems: "center", marginBottom: 16 }}>
        {/* search */}
        <div style={{ position: "relative", flex: "1 1 260px", maxWidth: 360 }}>
          <Icon name="search" size={17} style={{ position: "absolute", left: 14, top: 13, color: "var(--muted)" }} />
          <input className="input" value={q} onChange={(e) => chSearch(e.target.value)}
            placeholder="Search client, phone, or property" style={{ paddingLeft: 42 }} />
          {q && (
            <button onClick={() => chSearch("")} style={{ position: "absolute", right: 8, top: 9, width: 28, height: 28, borderRadius: 7,
              border: "none", background: "transparent", color: "var(--muted)", cursor: "pointer", display: "grid", placeItems: "center" }}>
              <Icon name="x" size={15} />
            </button>
          )}
        </div>

        <FilterSelect icon="filter" value={status} options={statusOptions} onChange={chStatus} />

        {leadStatusOptions && (
          <FilterSelect icon="list" value={leadStatus} options={leadStatusOptions} onChange={chLeadStatus} />
        )}

        <AsyncFilterSelect icon="user"   selected={agentOpt} onSelect={chAgent} loadOptions={window.api.getAgents} placeholder="All agents" />

        <AsyncFilterSelect icon="mapPin" selected={stateOpt} onSelect={chState} loadOptions={window.api.getStates} placeholder="All states" />

        <FilterSelect icon="calendar" value={days} options={dayOptions} onChange={chDays} />

        {hasFilters && (
          <button className="btn btn-ghost btn-sm" onClick={resetFilters}>
            <Icon name="refresh" size={15} /> Reset
          </button>
        )}

        <div style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: 10 }}>
          <div style={{ fontSize: 13, color: "var(--muted)", fontWeight: 600 }}>
            {loading ? "Loading..." : `${totalCount} ${totalCount === 1 ? "lead" : "leads"}`}
          </div>
          <button className="btn btn-outline btn-sm" onClick={doExport} disabled={exportBusy}
            style={{ opacity: exportBusy ? 0.55 : 1, display: "flex", alignItems: "center", gap: 6 }}>
            <Icon name="download" size={14} />
            {exportBusy ? "Exporting…" : "Export"}
          </button>
        </div>
      </div>

      {/* table */}
      <div className="card" style={{ padding: 0, overflow: "hidden" }}>
        <div className="thin-scroll" style={{ overflowX: "auto" }}>
          <table className="tbl" style={{ minWidth: 920, "--row-pad": rowPad }}>
            <thead>
              <tr>
                <th style={{ paddingTop: 16 }}>Submitted</th>
                <th>Client</th>
                <th>Property</th>
                <th>Type</th>
                <th>Pre-qual</th>
                <th>Status</th>
                <th>Lead Status</th>
                <th>Assigned agent</th>
                <th style={{ textAlign: "center" }}>Notes</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {loading
                ? Array.from({ length: 6 }).map((_, i) => <SkeletonRow key={i} />)
                : leads.map((l) => <LeadRow key={l.id} l={l} onOpen={onOpen} compact={compact} />)}
            </tbody>
          </table>
        </div>
        {!loading && leads.length === 0 && <EmptyState hasFilters={hasFilters} onReset={resetFilters} />}
      </div>

      {/* pagination */}
      {!loading && (hasNext || hasPrev) && (
        <div style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 12, marginTop: 20 }}>
          <button className="btn btn-outline btn-sm" disabled={!hasPrev} onClick={() => gotoPage(page - 1)}
            style={{ opacity: hasPrev ? 1 : 0.4 }}>
            ← Prev
          </button>
          <span style={{ fontSize: 13, fontWeight: 600, color: "var(--muted)", minWidth: 120, textAlign: "center" }}>
            Page {page}{totalCount ? ` of ${Math.ceil(totalCount / PAGE_SIZE)}` : ""}
            <span style={{ fontWeight: 400, marginLeft: 6 }}>({totalCount} total)</span>
          </span>
          <button className="btn btn-outline btn-sm" disabled={!hasNext} onClick={() => gotoPage(page + 1)}
            style={{ opacity: hasNext ? 1 : 0.4 }}>
            Next →
          </button>
        </div>
      )}
    </div>
  );
}

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

function Stat({ label, value, tone }) {
  const colors = { navy: "var(--navy)", emerald: "var(--emerald)", blue: "var(--blue)", neutral: "var(--muted)" };
  return (
    <div className="card" style={{ padding: "11px 18px", minWidth: 96, boxShadow: "var(--card-shadow-2)" }}>
      <div style={{ fontSize: 22, fontWeight: 800, color: colors[tone], lineHeight: 1.1, letterSpacing: "-.02em" }}>{value}</div>
      <div style={{ fontSize: 12, color: "var(--muted)", fontWeight: 600, marginTop: 2 }}>{label}</div>
    </div>
  );
}

// Simple <select> dropdown — accepts {value, label} objects or plain strings
function FilterSelect({ icon, value, options, onChange }) {
  return (
    <div style={{ position: "relative" }}>
      <Icon name={icon} size={16} style={{ position: "absolute", left: 13, top: 14, color: "var(--muted)", pointerEvents: "none" }} />
      <select className="select" value={value} onChange={(e) => onChange(e.target.value)}
        style={{ paddingLeft: 38, width: "auto", minWidth: 148, fontWeight: 600, color: "var(--label-2)" }}>
        {(options || []).map((o) => {
          const val   = typeof o === "object" ? o.value : o;
          const label = typeof o === "object" ? o.label : o;
          return <option key={val} value={val}>{label}</option>;
        })}
      </select>
    </div>
  );
}

// Async searchable dropdown for agent and state filters
function AsyncFilterSelect({ icon, selected, onSelect, loadOptions, placeholder }) {
  const [open,     setOpen]     = React.useState(false);
  const [search,   setSearch]   = React.useState("");
  const [options,  setOptions]  = React.useState([]);
  const [fetching, setFetching] = React.useState(false);
  const ref   = React.useRef(null);
  const timer = React.useRef(null);

  // Close on outside click
  React.useEffect(() => {
    function h(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  }, []);

  // (Re)load options when dropdown opens or search changes
  React.useEffect(() => {
    if (!open) return;
    clearTimeout(timer.current);
    const delay = search ? 300 : 0;
    setFetching(true);
    timer.current = setTimeout(async () => {
      try {
        const opts = await loadOptions(search);
        setOptions(opts || []);
      } catch (_) {
        setOptions([]);
      } finally {
        setFetching(false);
      }
    }, delay);
    return () => clearTimeout(timer.current);
  }, [open, search]);

  const hasValue = !!selected.value;

  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button type="button"
        onClick={() => { setOpen((o) => !o); if (!open) setSearch(""); }}
        style={{ display: "flex", alignItems: "center", gap: 7, height: 46, padding: "0 12px 0 38px",
          border: "1px solid var(--field-border)", borderRadius: 11, background: "#fff", cursor: "pointer",
          fontFamily: "inherit", fontSize: 14, fontWeight: 600, color: hasValue ? "var(--navy)" : "var(--label-2)",
          minWidth: 148, position: "relative", whiteSpace: "nowrap" }}>
        <Icon name={icon} size={16} style={{ position: "absolute", left: 13, color: "var(--muted)" }} />
        <span style={{ flex: 1, textAlign: "left", overflow: "hidden", textOverflow: "ellipsis", maxWidth: 130 }}>
          {hasValue ? selected.label : placeholder}
        </span>
        {hasValue ? (
          <span
            onClick={(e) => { e.stopPropagation(); onSelect({ value: "", label: "" }); }}
            style={{ width: 17, height: 17, borderRadius: 99, background: "#C4C9D1", color: "#fff",
              display: "grid", placeItems: "center", flexShrink: 0, fontSize: 12, lineHeight: 1, cursor: "pointer" }}>
            ×
          </span>
        ) : (
          <Icon name="chevDown" size={14} style={{ color: "var(--muted)", flexShrink: 0 }} />
        )}
      </button>

      {open && (
        <div style={{ position: "absolute", top: "calc(100% + 6px)", left: 0, zIndex: 110, background: "#fff",
          border: "1px solid var(--border)", borderRadius: 12, boxShadow: "var(--card-shadow)",
          minWidth: 230, animation: "fadeUp .15s ease both" }}>
          <div style={{ padding: "8px 10px", borderBottom: "1px solid var(--border)" }}>
            <input className="input" value={search} onChange={(e) => setSearch(e.target.value)}
              placeholder="Search..." autoFocus style={{ height: 34, fontSize: 13, padding: "0 10px" }} />
          </div>
          <div className="thin-scroll" style={{ maxHeight: 210, overflowY: "auto", padding: "4px 0" }}>
            <div
              onClick={() => { onSelect({ value: "", label: "" }); setOpen(false); }}
              style={{ padding: "8px 14px", cursor: "pointer", fontSize: 13.5, fontWeight: 600, color: "var(--muted)", fontStyle: "italic" }}
              onMouseEnter={(e) => e.currentTarget.style.background = "#F7F8FA"}
              onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
              {placeholder}
            </div>
            {fetching ? (
              <div style={{ padding: "8px 14px", color: "var(--muted)", fontSize: 13 }}>Loading…</div>
            ) : options.length === 0 ? (
              <div style={{ padding: "8px 14px", color: "var(--muted)", fontSize: 13 }}>No results</div>
            ) : options.map((o) => {
              const isActive = selected.value === o.value;
              return (
                <div key={o.value}
                  onClick={() => { onSelect(o); setOpen(false); }}
                  style={{ padding: "8px 14px", cursor: "pointer", fontSize: 13.5, fontWeight: 600,
                    color: isActive ? "var(--accent)" : "var(--foreground)",
                    background: isActive ? "var(--accent-soft)" : "transparent" }}
                  onMouseEnter={(e) => { if (!isActive) e.currentTarget.style.background = "#F7F8FA"; }}
                  onMouseLeave={(e) => { if (!isActive) e.currentTarget.style.background = "transparent"; }}>
                  {o.label}
                </div>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

function LeadRow({ l, onOpen, compact }) {
  const addr      = [l.city, l.state].filter(Boolean).join(", ");
  const noteCount = typeof l.note_count === "number" ? l.note_count : (l.comments || []).length;
  return (
    <tr onClick={() => onOpen(l)}>
      <td>
        <div style={{ fontWeight: 600, fontSize: 13.5 }}>{fmtDate(l.created)}</div>
        <div style={{ fontSize: 12, color: "var(--muted)" }}>{relTime(l.created)}</div>
      </td>
      <td>
        <div style={{ fontWeight: 700, fontSize: 14, color: "var(--foreground)" }}>{l.name}</div>
        <div style={{ fontSize: 12.5, color: "var(--muted)", display: "flex", alignItems: "center", gap: 5, marginTop: 1 }}>
          <Icon name="phone" size={11.5} /> {l.phone}
        </div>
      </td>
      <td>
        {l.street && <div style={{ fontWeight: 600, fontSize: 13.5 }}>{l.street}</div>}
        <div style={{ fontSize: l.street ? 12.5 : 13.5, color: l.street ? "var(--muted)" : "var(--foreground)", fontWeight: l.street ? 500 : 600 }}>
          {addr || "—"}
        </div>
      </td>
      <td>
        <div style={{ display: "flex", gap: 5, flexWrap: "wrap" }}>{(l.types || []).map((t) => <TypeChip key={t} t={t} />)}</div>
      </td>
      <td>{l.preQual ? (<PreQualPill v={l.preQual} />) : "-"}</td>
      <td><StatusBadge status={l.status} /></td>
      <td style={{ fontSize: 13.5, color: l.lead_status ? "var(--foreground)" : "var(--muted)", fontWeight: l.lead_status ? 600 : 400 }}>
        {l.lead_status || "—"}
      </td>
      <td>
        {l.agent ? (
          <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
            <Avatar agent={l.agent} size={30} />
            <div style={{ lineHeight: 1.25, whiteSpace: "nowrap" }}>
              <div style={{ fontWeight: 600, fontSize: 13.5 }}>{l.agent.name}</div>
              {l.agent.office && <div style={{ fontSize: 11.5, color: "var(--muted)" }}>{l.agent.office}</div>}
            </div>
          </div>
        ) : (
          <span style={{ color: "var(--muted)", fontSize: 13.5, fontStyle: "italic" }}>Unassigned</span>
        )}
      </td>
      <td style={{ textAlign: "center" }}>
        {noteCount > 0 ? (
          <span style={{ display: "inline-flex", alignItems: "center", gap: 5, color: "var(--blue)", fontWeight: 700, fontSize: 13 }}>
            <Icon name="message" size={15} /> {noteCount}
          </span>
        ) : (
          <span style={{ color: "#C4C9D1" }}><Icon name="message" size={15} /></span>
        )}
      </td>
      <td style={{ width: 30 }}>
        <Icon name="chevRight" size={17} style={{ color: "#C4C9D1" }} />
      </td>
    </tr>
  );
}

function SkeletonRow() {
  return (
    <tr style={{ cursor: "default" }}>
      <td><div className="sk" style={{ width: 80, height: 13 }}></div><div className="sk" style={{ width: 52, height: 11, marginTop: 6 }}></div></td>
      <td><div className="sk" style={{ width: 120, height: 14 }}></div><div className="sk" style={{ width: 90, height: 11, marginTop: 6 }}></div></td>
      <td><div className="sk" style={{ width: 130, height: 13 }}></div></td>
      <td><div className="sk" style={{ width: 46, height: 22, borderRadius: 7 }}></div></td>
      <td><div className="sk" style={{ width: 54, height: 22, borderRadius: 99 }}></div></td>
      <td><div className="sk" style={{ width: 96, height: 24, borderRadius: 99 }}></div></td>
      <td><div className="sk" style={{ width: 96, height: 24, borderRadius: 99 }}></div></td>
      <td><div style={{ display: "flex", gap: 9, alignItems: "center" }}><div className="sk" style={{ width: 30, height: 30, borderRadius: 99 }}></div><div className="sk" style={{ width: 90, height: 13 }}></div></div></td>
      <td><div className="sk" style={{ width: 22, height: 18, margin: "0 auto" }}></div></td>
      <td></td>
    </tr>
  );
}

function EmptyState({ hasFilters, onReset }) {
  return (
    <div style={{ padding: "64px 24px", textAlign: "center" }}>
      <div style={{ width: 72, height: 72, borderRadius: 18, background: "var(--accent-soft)", margin: "0 auto 18px",
        display: "grid", placeItems: "center", color: "var(--accent)" }}>
        <Icon name={hasFilters ? "search" : "inbox"} size={32} stroke={1.8} />
      </div>
      <div style={{ fontWeight: 700, fontSize: 17, color: "var(--navy)", marginBottom: 6 }}>
        {hasFilters ? "No leads match your filters" : "No leads yet"}
      </div>
      <div style={{ color: "var(--muted)", fontSize: 14, maxWidth: 360, margin: "0 auto 20px" }}>
        {hasFilters
          ? "Try a different search term, status, or date range."
          : "Log your first lead and it will appear here with its assigned agent and status."}
      </div>
      {hasFilters && (
        <button className="btn btn-outline btn-sm" onClick={onReset}><Icon name="refresh" size={15} /> Reset filters</button>
      )}
    </div>
  );
}

window.TrackingTable = TrackingTable;
