// ERP Transactions tab — full financial activity feed for a project

const formatShortDate = (iso) => {
  const d = new Date(iso + "T12:00:00");
  return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
};

const TX_TYPES = {
  invoice:     { label: "Invoice",            short: "Invoice",       icon: "receipt",   color: "#22863A", flow: "revenue", desc: "Customer invoice" },
  salesOrder:  { label: "Sales Order",        short: "SO",            icon: "tag",       color: "#22863A", flow: "revenue", desc: "Customer order" },
  paymentRcv:  { label: "Payment Received",   short: "Pmt In",        icon: "arrowDown", color: "#22863A", flow: "revenue", desc: "Payment from customer" },
  po:          { label: "Purchase Order",     short: "PO",            icon: "shoppingCart", color: "#534AFF", flow: "commit", desc: "Vendor commitment" },
  bill:        { label: "Vendor Bill",        short: "Bill",          icon: "file",      color: "#FF9143", flow: "cost",   desc: "Cost from vendor" },
  vendorPmt:   { label: "Vendor Payment",     short: "Pmt Out",       icon: "arrowUp",   color: "#FF9143", flow: "cost",   desc: "Payment to vendor" },
  journal:     { label: "Journal Entry",      short: "JE",            icon: "pen",      color: "#76ADFF", flow: "neutral",desc: "Manual accounting adj." },
  inventory:   { label: "Inventory",          short: "Inv",           icon: "archive",   color: "#B279FF", flow: "cost",   desc: "Inventory transaction" },
  labor:       { label: "Time / Labor",       short: "Labor",         icon: "clock",     color: "#534AFF", flow: "cost",   desc: "Labor hours" },
  sub:         { label: "Subcontractor",      short: "Sub",           icon: "users",     color: "#FF9143", flow: "cost",   desc: "Subcontractor cost" },
  receipt:     { label: "Goods Receipt",      short: "GR",            icon: "package",   color: "#76ADFF", flow: "neutral",desc: "Materials received" },
};

const ERP_TX = [
  { id: "INV-2026-0148", type: "invoice", date: "2026-04-28", party: "Cedar Heights Holdings", description: "Pay App #4 — April progress billing", amount:  642_000, status: "Sent",      scope: "PV-300 Tracker Install", by: { initials: "MI", name: "Maya Iyer", color: "#B279FF" }, updated: "2d ago", erp: "QuickBooks" },
  { id: "BILL-9421",     type: "bill",    date: "2026-04-29", party: "PileForce Inc.",          description: "Pile-driving labor — Week 17",          amount:  148_200, status: "Open",      scope: "PV-100 Foundations",     by: { initials: "RF", name: "Robert Fox", color: "#76ADFF" }, updated: "1d ago", erp: "QuickBooks" },
  { id: "PO-3318",       type: "po",      date: "2026-04-26", party: "Sundance Modules",        description: "Bifacial modules — Lot 3 (8,400 ea)",   amount:  892_400, status: "Approved",  scope: "PV-200 Modules",         by: { initials: "EC", name: "Emma Connor", color: "#22863A" }, updated: "4d ago", erp: "Sage Intacct" },
  { id: "PMT-7741",      type: "paymentRcv", date: "2026-04-25", party: "Cedar Heights Holdings", description: "ACH — Pay App #3",                    amount:  478_600, status: "Cleared",   scope: null,                     by: { initials: "MI", name: "Maya Iyer", color: "#B279FF" }, updated: "5d ago", erp: "QuickBooks" },
  { id: "VP-6612",       type: "vendorPmt", date: "2026-04-24", party: "Apex Civil",            description: "Pay App #2 — Civil package",           amount:  214_800, status: "Cleared",   scope: "PV-100 Foundations",     by: { initials: "MI", name: "Maya Iyer", color: "#B279FF" }, updated: "6d ago", erp: "QuickBooks" },
  { id: "BILL-9408",     type: "bill",    date: "2026-04-23", party: "ElectroPro",              description: "DC cable — Reel 14 (delivered)",        amount:   86_300, status: "Approved",  scope: "PV-400 Electrical",      by: { initials: "JL", name: "Jordan Lin", color: "#FF9143" }, updated: "7d ago", erp: "QuickBooks" },
  { id: "GR-5021",       type: "receipt", date: "2026-04-23", party: "ElectroPro",              description: "Goods receipt — DC cable Reel 14",      amount:   86_300, status: "Posted",    scope: "PV-400 Electrical",      by: { initials: "JL", name: "Jordan Lin", color: "#FF9143" }, updated: "7d ago", erp: "Sage Intacct" },
  { id: "TIME-W17",      type: "labor",   date: "2026-04-22", party: "Mindworks Field Crew",    description: "Week 17 — 4 crews, 1,184 hrs (Procore import)", amount: 89_440, status: "Posted", scope: "PV-100 Foundations", by: { initials: "EC", name: "Emma Connor", color: "#22863A" }, updated: "8d ago", erp: "Procore → QB" },
  { id: "SUB-2204",      type: "sub",     date: "2026-04-21", party: "Nextracker",              description: "Tracker install commissioning support",  amount:   42_000, status: "Open",      scope: "PV-300 Tracker Install", by: { initials: "RF", name: "Robert Fox", color: "#76ADFF" }, updated: "9d ago", erp: "QuickBooks" },
  { id: "INV-2026-0142", type: "invoice", date: "2026-04-18", party: "Cedar Heights Holdings",  description: "CO-012 — Owner-directed module swap",   amount:   88_200, status: "Paid",      scope: "PV-200 Modules",         by: { initials: "MI", name: "Maya Iyer", color: "#B279FF" }, updated: "12d ago", erp: "QuickBooks" },
  { id: "JE-1108",       type: "journal", date: "2026-04-17", party: "Internal",                description: "Reclass — Predrill labor to CO-013",     amount:   18_600, status: "Posted",    scope: "PV-100 Foundations",     by: { initials: "MI", name: "Maya Iyer", color: "#B279FF" }, updated: "13d ago", erp: "QuickBooks" },
  { id: "INV-9817",      type: "inventory", date: "2026-04-15", party: "Warehouse 4",           description: "Inventory issue — torque tubes (480 ea)", amount:  124_800, status: "Posted",    scope: "PV-300 Tracker Install", by: { initials: "EC", name: "Emma Connor", color: "#22863A" }, updated: "15d ago", erp: "Sage Intacct" },
  { id: "PO-3304",       type: "po",      date: "2026-04-14", party: "Nextracker",              description: "Tracker steel — Lot 2 (3,200 tubes)",    amount:  616_000, status: "Approved",  scope: "PV-300 Tracker Install", by: { initials: "RF", name: "Robert Fox", color: "#76ADFF" }, updated: "16d ago", erp: "Sage Intacct" },
  { id: "SO-2210",       type: "salesOrder", date: "2026-04-12", party: "Cedar Heights Holdings", description: "Master sales order — base contract",  amount: 4_850_000, status: "Active",    scope: null,                     by: { initials: "MI", name: "Maya Iyer", color: "#B279FF" }, updated: "18d ago", erp: "QuickBooks" },
  { id: "BILL-9388",     type: "bill",    date: "2026-04-10", party: "Apex Civil",              description: "Earthwork — final mass grading",        amount:   72_400, status: "Pending",   scope: "PV-100 Foundations",     by: { initials: "RF", name: "Robert Fox", color: "#76ADFF" }, updated: "20d ago", erp: "QuickBooks" },
  { id: "TIME-W16",      type: "labor",   date: "2026-04-15", party: "Mindworks Field Crew",    description: "Week 16 — 4 crews, 1,212 hrs",          amount:   92_120, status: "Posted",    scope: "PV-100 Foundations",     by: { initials: "EC", name: "Emma Connor", color: "#22863A" }, updated: "15d ago", erp: "Procore → QB" },
  { id: "VP-6588",       type: "vendorPmt", date: "2026-04-08", party: "Sundance Modules",      description: "Deposit — Lot 2 modules",               amount:  178_480, status: "Cleared",   scope: "PV-200 Modules",         by: { initials: "MI", name: "Maya Iyer", color: "#B279FF" }, updated: "22d ago", erp: "QuickBooks" },
  { id: "GR-4988",       type: "receipt", date: "2026-04-07", party: "Sundance Modules",        description: "Goods receipt — modules Lot 2 (4,200 ea)", amount: 446_200, status: "Posted",  scope: "PV-200 Modules",         by: { initials: "EC", name: "Emma Connor", color: "#22863A" }, updated: "23d ago", erp: "Sage Intacct" },
];

const STATUS_TONES_TX = {
  Open:     "warning",  Pending: "warning",  Sent:     "info",
  Approved: "success",  Paid:    "success",  Cleared:  "success",
  Posted:   "success",  Active:  "info",     Closed:   "neutral",
  Draft:    "neutral",  Void:    "danger",
};

const cellNoWrap = { whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0 };
const flowColor = (flow) => flow === "revenue" ? "rgb(34,134,58)" : flow === "cost" ? "rgb(192,47,50)" : flow === "commit" ? "rgb(83,74,255)" : "rgb(106,115,131)";
const flowSign  = (flow) => flow === "revenue" ? "+" : flow === "cost" ? "−" : "";
const fmtMoney  = (n) => "$" + Math.abs(n).toLocaleString();

const ERPTransactionsTab = ({ p }) => {
  const [activeTypes, setActiveTypes] = React.useState(["all"]);
  const [statusFilter, setStatusFilter] = React.useState("All");
  const [partyFilter, setPartyFilter] = React.useState("All");
  const [rangeFilter, setRangeFilter] = React.useState("Last 90 days");
  const [amountFilter, setAmountFilter] = React.useState("All");
  const [search, setSearch] = React.useState("");
  const [selectedTx, setSelectedTx] = React.useState(null);

  const toggleType = (id) => {
    if (id === "all") return setActiveTypes(["all"]);
    setActiveTypes(prev => {
      const next = prev.filter(x => x !== "all" && x !== id);
      if (!prev.includes(id)) next.push(id);
      return next.length === 0 ? ["all"] : next;
    });
  };

  const counts = Object.keys(TX_TYPES).reduce((acc, k) => {
    acc[k] = ERP_TX.filter(t => t.type === k).length;
    return acc;
  }, { all: ERP_TX.length });

  const parties = ["All", ...Array.from(new Set(ERP_TX.map(t => t.party)))];

  const filtered = ERP_TX.filter(t => {
    if (!activeTypes.includes("all") && !activeTypes.includes(t.type)) return false;
    if (statusFilter !== "All" && t.status !== statusFilter) return false;
    if (partyFilter !== "All" && t.party !== partyFilter) return false;
    if (search && !(`${t.id} ${t.party} ${t.description}`.toLowerCase()).includes(search.toLowerCase())) return false;
    return true;
  });

  // Summary metrics (always reflect the project, not the active filter)
  const sumByFlow = (flow) => ERP_TX.filter(t => TX_TYPES[t.type].flow === flow).reduce((s, t) => s + t.amount, 0);
  const totalCost = ERP_TX.filter(t => ["bill", "labor", "sub", "inventory"].includes(t.type)).reduce((s, t) => s + t.amount, 0);
  const totalRevenue = ERP_TX.filter(t => t.type === "invoice").reduce((s, t) => s + t.amount, 0);
  const committed = ERP_TX.filter(t => t.type === "po" && t.status === "Approved").reduce((s, t) => s + t.amount, 0);
  const pending = ERP_TX.filter(t => ["Open", "Pending"].includes(t.status) && TX_TYPES[t.type].flow === "cost").reduce((s, t) => s + t.amount, 0);
  const margin = totalRevenue - totalCost;
  const marginPct = totalRevenue ? Math.round(margin / totalRevenue * 100) : 0;

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
      {/* Header */}
      <div>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }}>
          <h2 style={{ fontSize: 18, fontWeight: 600, margin: 0, letterSpacing: "-.01em" }}>ERP Transactions</h2>
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <span style={{ fontSize: 11, color: "rgb(106,115,131)", display: "inline-flex", alignItems: "center", gap: 4 }}>
              <span style={{ width: 6, height: 6, borderRadius: "50%", background: "rgb(34,134,58)" }} />
              Synced 14m ago · QuickBooks · Sage Intacct · Procore
            </span>
            <Button size="sm" kind="ghost" icon="refresh">Sync now</Button>
            <Button size="sm" kind="ghost" icon="download">Export</Button>
          </div>
        </div>
        <div style={{ fontSize: 13, color: "rgb(106,115,131)" }}>
          All financial and operational transactions linked to this project via the Project Dimension.
        </div>
      </div>

      {/* Summary cards */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 12 }}>
        <SummaryCard label="Total Revenue"  value={fmtMoney(totalRevenue)} flow="revenue" delta="+12% vs prior"   icon="trending"      sub={`${ERP_TX.filter(t=>t.type==="invoice").length} invoices`} />
        <SummaryCard label="Total Cost"     value={fmtMoney(totalCost)}    flow="cost"    delta="+8% vs prior"    icon="trendingDown"  sub={`${ERP_TX.filter(t=>["bill","labor","sub","inventory"].includes(t.type)).length} entries`} />
        <SummaryCard label="Committed Cost" value={fmtMoney(committed)}    flow="commit"  delta={null}            icon="shoppingCart"  sub={`${ERP_TX.filter(t=>t.type==="po"&&t.status==="Approved").length} open POs`} />
        <SummaryCard label="Pending Cost"   value={fmtMoney(pending)}      flow="neutral" delta={null}            icon="clock"         sub={`${ERP_TX.filter(t=>["Open","Pending"].includes(t.status)&&TX_TYPES[t.type].flow==="cost").length} bills awaiting`} />
        <SummaryCard label="Margin"         value={fmtMoney(margin)}       flow={margin>=0?"revenue":"cost"} delta={`${marginPct}%`} deltaTone={marginPct>=15?"success":"warning"} icon="dollar" sub="Revenue − Cost" highlight />
      </div>

      {/* Toolbar — type multiselect + secondary filters + search */}
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, flexWrap: "wrap" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
          <TypeMultiSelect activeTypes={activeTypes} counts={counts} onToggle={toggleType} />
          <FilterPill2Click label="Status" value={statusFilter}
            options={["All", "Open", "Pending", "Approved", "Paid", "Cleared", "Posted", "Sent", "Active"]}
            onChange={setStatusFilter} icon="flag" />
          <FilterPill2Click label="Vendor / Customer" value={partyFilter} options={parties} onChange={setPartyFilter} icon="briefcase" />
          <FilterPill2Click label="Date" value={rangeFilter} options={["Last 30 days", "Last 90 days", "This year", "All time"]} onChange={setRangeFilter} icon="calendar" />
          <FilterPill2Click label="Amount" value={amountFilter} options={["All", "< $10k", "$10k–$100k", "$100k–$500k", "> $500k"]} onChange={setAmountFilter} icon="dollar" />
          {(activeTypes.length > 1 || (!activeTypes.includes("all") && activeTypes.length === 1) || statusFilter !== "All" || partyFilter !== "All" || amountFilter !== "All") && (
            <button onClick={() => { setActiveTypes(["all"]); setStatusFilter("All"); setPartyFilter("All"); setAmountFilter("All"); }} style={{
              fontSize: 12, color: "rgb(83,74,255)", background: "transparent", border: "none",
              cursor: "pointer", fontFamily: "inherit", fontWeight: 500, padding: "4px 8px"
            }}>Clear filters</button>
          )}
        </div>
        <div style={{ position: "relative", width: 240 }}>
          <span style={{ position: "absolute", left: 10, top: 8, opacity: 0.5 }}>
            <Icon name="search" size={14} color="rgb(106,115,131)" />
          </span>
          <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Search ID, vendor, description…" style={{
            width: "100%", boxSizing: "border-box", paddingLeft: 30, paddingRight: 10, height: 30, borderRadius: 9999,
            border: "1px solid rgb(213,219,225)", fontSize: 13, fontFamily: "inherit", outline: "none", background: "#fff"
          }} />
        </div>
      </div>

      {/* Result count */}
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", fontSize: 12, color: "rgb(106,115,131)" }}>
        <span><strong style={{ color: "rgb(26,27,37)", fontWeight: 600 }}>{filtered.length}</strong> of {ERP_TX.length} transactions</span>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 12 }}>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }}>
            <span style={{ width: 8, height: 8, borderRadius: 2, background: "rgb(34,134,58)" }} />
            Revenue
          </span>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }}>
            <span style={{ width: 8, height: 8, borderRadius: 2, background: "rgb(192,47,50)" }} />
            Cost
          </span>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }}>
            <span style={{ width: 8, height: 8, borderRadius: 2, background: "rgb(83,74,255)" }} />
            Commitment
          </span>
        </span>
      </div>

      {/* Table */}
      {filtered.length === 0 ? (
        <FilteredEmpty onReset={() => { setActiveTypes(["all"]); setStatusFilter("All"); setPartyFilter("All"); setAmountFilter("All"); setSearch(""); }} />
      ) : (
        <Card padding={0}>
          <div style={{
            display: "grid",
            gridTemplateColumns: "170px 86px minmax(0, 1fr) minmax(0, 1.3fr) 110px 90px 36px 36px",
            padding: "10px 16px", fontSize: 11, fontWeight: 600, color: "rgb(106,115,131)",
            background: "rgb(252,252,253)", borderBottom: "1px solid rgb(239,240,242)",
            textTransform: "uppercase", letterSpacing: ".04em", gap: 12, alignItems: "center"
          }}>
            <span style={cellNoWrap}>Type / Number</span>
            <span style={cellNoWrap}>Date</span>
            <span style={cellNoWrap}>Vendor / Customer</span>
            <span style={cellNoWrap}>Description</span>
            <span style={{ ...cellNoWrap, textAlign: "right" }}>Amount</span>
            <span style={cellNoWrap}>Status</span>
            <span style={{ ...cellNoWrap, textAlign: "center" }}>By</span>
            <span></span>
          </div>
          {filtered.map((t, i) => {
            const ty = TX_TYPES[t.type];
            const isSel = selectedTx?.id === t.id;
            return (
              <div key={t.id} onClick={() => setSelectedTx(t)} style={{
                display: "grid",
                gridTemplateColumns: "170px 86px minmax(0, 1fr) minmax(0, 1.3fr) 110px 90px 36px 36px",
                padding: "12px 16px", gap: 12, alignItems: "center",
                borderBottom: i < filtered.length - 1 ? "1px solid rgb(239,240,242)" : "none",
                fontSize: 13, cursor: "pointer", transition: "background 120ms",
                background: isSel ? "rgb(248,248,251)" : "#fff",
                borderLeft: isSel ? "3px solid rgb(83,74,255)" : "3px solid transparent",
                paddingLeft: isSel ? 13 : 16
              }}
              onMouseEnter={e => { if (!isSel) e.currentTarget.style.background = "rgb(252,252,253)"; }}
              onMouseLeave={e => { if (!isSel) e.currentTarget.style.background = "#fff"; }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
                  <div style={{
                    width: 28, height: 28, borderRadius: 6, background: `${ty.color}1A`, color: ty.color,
                    display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0
                  }}>
                    <Icon name={ty.icon} size={13} color={ty.color} />
                  </div>
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontWeight: 600, fontSize: 12, color: "rgb(26,27,37)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", fontFamily: "ui-monospace, SF Mono, monospace" }}>{t.id}</div>
                    <div style={{ fontSize: 10, color: "rgb(106,115,131)", marginTop: 1 }}>{ty.short}</div>
                  </div>
                </div>
                <span style={{ ...cellNoWrap, fontSize: 12, fontVariantNumeric: "tabular-nums", color: "rgb(65,69,82)" }}>{formatShortDate(t.date)}</span>
                <span style={{ ...cellNoWrap, fontSize: 13, color: "rgb(26,27,37)" }} title={t.party}>{t.party}</span>
                <div style={{ minWidth: 0 }}>
                  <div style={{ ...cellNoWrap, fontSize: 12, color: "rgb(65,69,82)" }} title={t.description}>{t.description}</div>
                  {t.scope && <div style={{ ...cellNoWrap, fontSize: 10, color: "rgb(106,115,131)", marginTop: 2 }} title={t.scope}>{t.scope}</div>}
                </div>
                <span style={{
                  textAlign: "right", fontSize: 13, fontWeight: 600,
                  fontVariantNumeric: "tabular-nums", color: flowColor(ty.flow), whiteSpace: "nowrap"
                }}>
                  {flowSign(ty.flow)}{fmtMoney(t.amount)}
                </span>
                <span style={cellNoWrap}>
                  <Chip tone={STATUS_TONES_TX[t.status] || "neutral"}>{t.status}</Chip>
                </span>
                <span style={{ display: "inline-flex", alignItems: "center", justifyContent: "center" }} title={`${t.by.name} · via ${t.erp}`}>
                  <Avatar size={22} initials={t.by.initials} color={t.by.color} />
                </span>
                <span style={{ display: "flex", justifyContent: "flex-end" }}>
                  <Icon name="chevronRight" size={14} color="rgb(163,172,186)" />
                </span>
              </div>
            );
          })}
        </Card>
      )}

      {selectedTx && <TxDetailDrawer tx={selectedTx} onClose={() => setSelectedTx(null)} />}
    </div>
  );
};

const SummaryCard = ({ label, value, flow, delta, deltaTone, sub, icon, highlight }) => {
  const color = flowColor(flow);
  return (
    <div style={{
      background: highlight ? "linear-gradient(180deg, rgba(232,233,246,.5) 0%, #fff 60%)" : "#fff",
      border: highlight ? "1px solid rgba(83,74,255,.25)" : "1px solid rgb(227,229,232)",
      borderRadius: 12, padding: "14px 16px", display: "flex", flexDirection: "column", gap: 8, minHeight: 108
    }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
        <span style={{ fontSize: 12, color: "rgb(106,115,131)", fontWeight: 500 }}>{label}</span>
        <div style={{
          width: 22, height: 22, borderRadius: 6,
          background: `${color}14`, display: "flex", alignItems: "center", justifyContent: "center"
        }}>
          <Icon name={icon} size={12} color={color} />
        </div>
      </div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 6 }}>
        <span style={{ fontSize: 22, fontWeight: 700, letterSpacing: "-.02em", fontVariantNumeric: "tabular-nums", color: highlight ? color : "rgb(26,27,37)" }}>{value}</span>
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: "auto", fontSize: 11 }}>
        {delta && (
          <span style={{
            display: "inline-flex", alignItems: "center", gap: 3, fontWeight: 600,
            color: deltaTone === "success" ? "rgb(34,134,58)" : deltaTone === "warning" ? "rgb(178,121,26)" : "rgb(106,115,131)"
          }}>
            <Icon name={delta.startsWith("+") || (deltaTone === "success") ? "arrowUp" : "arrowDown"} size={10} />
            {delta}
          </span>
        )}
        {sub && <span style={{ color: "rgb(106,115,131)" }}>{sub}</span>}
      </div>
    </div>
  );
};

const TypeMultiSelect = ({ activeTypes, counts, onToggle }) => {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef();

  React.useEffect(() => {
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, []);

  const allActive = activeTypes.includes("all");
  const selectedCount = allActive ? 0 : activeTypes.length;
  const summaryLabel = allActive
    ? "All types"
    : selectedCount === 1
      ? TX_TYPES[activeTypes[0]]?.label || "1 type"
      : `${selectedCount} types`;

  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button onClick={() => setOpen(o => !o)} style={{
        display: "inline-flex", alignItems: "center", gap: 6, height: 28, padding: "0 12px", borderRadius: 9999,
        border: selectedCount > 0 ? "1px solid rgba(83,74,255,.3)" : "1px solid rgb(227,229,232)",
        background: selectedCount > 0 ? "rgba(83,74,255,.08)" : "#fff",
        color: selectedCount > 0 ? "rgb(83,74,255)" : "rgb(65,69,82)",
        fontSize: 12, fontWeight: 500, cursor: "pointer", fontFamily: "inherit"
      }}>
        <Icon name="layers" size={12} color={selectedCount > 0 ? "rgb(83,74,255)" : "rgb(106,115,131)"} />
        <span style={{ color: "rgb(106,115,131)", fontWeight: 500 }}>Type:</span>
        <span style={{ fontWeight: 600 }}>{summaryLabel}</span>
        {selectedCount > 0 && (
          <span style={{
            fontSize: 10, fontWeight: 600, padding: "1px 6px", borderRadius: 9999,
            background: "rgba(83,74,255,.15)", color: "rgb(83,74,255)", fontVariantNumeric: "tabular-nums"
          }}>{selectedCount}</span>
        )}
        <Icon name="expandDown" size={11} color={selectedCount > 0 ? "rgb(83,74,255)" : "rgb(106,115,131)"} />
      </button>

      {open && (
        <div style={{
          position: "absolute", top: 32, left: 0, zIndex: 30, minWidth: 280,
          background: "#fff", border: "1px solid rgb(231,233,236)", borderRadius: 10,
          boxShadow: "0 12px 28px rgba(15,23,42,.12)", overflow: "hidden"
        }}>
          <div style={{ padding: "10px 12px", borderBottom: "1px solid rgb(239,240,242)", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
            <span style={{ fontSize: 11, color: "rgb(106,115,131)", fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em" }}>Filter by type</span>
            {!allActive && (
              <button onClick={() => onToggle("all")} style={{
                background: "transparent", border: "none", cursor: "pointer", fontSize: 11,
                color: "rgb(83,74,255)", fontWeight: 500, fontFamily: "inherit", padding: 0
              }}>Clear</button>
            )}
          </div>
          <div style={{ maxHeight: 360, overflowY: "auto", padding: 4 }}>
            <TypeRow checked={allActive} onClick={() => onToggle("all")}
              icon={null} label="All transactions" count={counts.all} />
            <div style={{ height: 1, background: "rgb(239,240,242)", margin: "4px 8px" }} />
            {Object.entries(TX_TYPES).map(([id, t]) => (
              <TypeRow key={id}
                checked={activeTypes.includes(id)}
                onClick={() => onToggle(id)}
                icon={t.icon} iconColor={t.color}
                label={t.label} count={counts[id] || 0} />
            ))}
          </div>
        </div>
      )}
    </div>
  );
};

const TypeRow = ({ checked, onClick, icon, iconColor, label, count }) => (
  <button onClick={onClick} style={{
    display: "flex", alignItems: "center", gap: 10, width: "100%", padding: "8px 10px",
    background: checked ? "rgba(83,74,255,.06)" : "transparent",
    border: "none", borderRadius: 6, cursor: "pointer", fontFamily: "inherit", fontSize: 13,
    color: "rgb(26,27,37)", textAlign: "left"
  }}
  onMouseEnter={e => { if (!checked) e.currentTarget.style.background = "rgb(248,248,251)"; }}
  onMouseLeave={e => { if (!checked) e.currentTarget.style.background = "transparent"; }}>
    <span style={{
      width: 16, height: 16, borderRadius: 4, flexShrink: 0,
      border: checked ? "1.5px solid rgb(83,74,255)" : "1.5px solid rgb(213,219,225)",
      background: checked ? "rgb(83,74,255)" : "#fff",
      display: "flex", alignItems: "center", justifyContent: "center"
    }}>
      {checked && <Icon name="check" size={10} color="#fff" />}
    </span>
    {icon && (
      <span style={{
        width: 22, height: 22, borderRadius: 5,
        background: `${iconColor}1A`, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0
      }}>
        <Icon name={icon} size={11} color={iconColor} />
      </span>
    )}
    <span style={{ flex: 1, fontWeight: checked ? 600 : 500 }}>{label}</span>
    <span style={{
      fontSize: 11, fontWeight: 600, padding: "1px 6px", borderRadius: 9999,
      background: checked ? "rgba(83,74,255,.15)" : "rgb(241,242,244)",
      color: checked ? "rgb(83,74,255)" : "rgb(106,115,131)",
      fontVariantNumeric: "tabular-nums"
    }}>{count}</span>
  </button>
);

const TypePill = ({ id, label, icon, color, count, active, onClick }) => (
  <button onClick={onClick} style={{
    display: "inline-flex", alignItems: "center", gap: 6, padding: "5px 10px", borderRadius: 9999,
    border: active ? "1px solid rgba(83,74,255,.3)" : "1px solid rgb(227,229,232)",
    background: active ? "rgba(83,74,255,.08)" : "#fff",
    color: active ? "rgb(83,74,255)" : "rgb(65,69,82)",
    fontSize: 12, fontWeight: 500, cursor: "pointer", fontFamily: "inherit",
    transition: "all 120ms"
  }}
  onMouseEnter={e => { if (!active) e.currentTarget.style.background = "rgb(248,248,251)"; }}
  onMouseLeave={e => { if (!active) e.currentTarget.style.background = "#fff"; }}>
    {icon && <Icon name={icon} size={12} color={active ? "rgb(83,74,255)" : (color || "rgb(106,115,131)")} />}
    {label}
    {count != null && (
      <span style={{
        fontSize: 10, fontWeight: 600, padding: "1px 6px", borderRadius: 9999,
        background: active ? "rgba(83,74,255,.15)" : "rgb(241,242,244)",
        color: active ? "rgb(83,74,255)" : "rgb(106,115,131)",
        fontVariantNumeric: "tabular-nums"
      }}>{count}</span>
    )}
  </button>
);

const FilteredEmpty = ({ onReset }) => (
  <div style={{
    background: "#fff", border: "1px dashed rgb(213,219,225)", borderRadius: 12,
    padding: "48px 24px", display: "flex", flexDirection: "column", alignItems: "center", gap: 12, textAlign: "center"
  }}>
    <div style={{ width: 56, height: 56, borderRadius: "50%", background: "rgb(248,248,251)", display: "flex", alignItems: "center", justifyContent: "center" }}>
      <Icon name="search" size={22} color="rgb(163,172,186)" />
    </div>
    <div>
      <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 4 }}>No transactions match your filters</div>
      <div style={{ fontSize: 12, color: "rgb(106,115,131)" }}>Try clearing filters or searching for a different ID, vendor, or description.</div>
    </div>
    <Button kind="ghost" size="sm" onClick={onReset}>Clear all filters</Button>
  </div>
);

// =================================================================
// TRANSACTION DETAIL DRAWER
// =================================================================

const TxDetailDrawer = ({ tx, onClose }) => {
  const ty = TX_TYPES[tx.type];

  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  const lineItems = mockLineItems(tx);
  const timeline = mockTimeline(tx);

  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, background: "rgba(15,23,42,.35)",
      display: "flex", justifyContent: "flex-end", zIndex: 1000
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: 560, maxWidth: "100vw", height: "100%", background: "#fff",
        boxShadow: "-12px 0 40px rgba(15,23,42,.16)",
        display: "flex", flexDirection: "column", overflow: "hidden",
        animation: "slideIn 240ms cubic-bezier(.2,.6,.2,1)"
      }}>
        <style>{`@keyframes slideIn { from { transform: translateX(40px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }`}</style>

        {/* Header */}
        <div style={{ padding: "16px 20px", borderBottom: "1px solid rgb(239,240,242)" }}>
          <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12, marginBottom: 12 }}>
            <div style={{ display: "flex", gap: 12, minWidth: 0 }}>
              <div style={{
                width: 40, height: 40, borderRadius: 10,
                background: `${ty.color}1A`, color: ty.color,
                display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0
              }}>
                <Icon name={ty.icon} size={18} color={ty.color} />
              </div>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 11, color: "rgb(106,115,131)", fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em", marginBottom: 2 }}>{ty.label}</div>
                <div style={{ fontSize: 16, fontWeight: 600, fontFamily: "ui-monospace, SF Mono, monospace" }}>{tx.id}</div>
              </div>
            </div>
            <div style={{ display: "flex", gap: 4 }}>
              <Button size="sm" kind="ghost" icon="link">Open in {tx.erp}</Button>
              <IconBtn icon="cross" size={30} tone="outline" onClick={onClose} />
            </div>
          </div>

          <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
            <Chip tone={STATUS_TONES_TX[tx.status] || "neutral"}>{tx.status}</Chip>
            <span style={{ width: 3, height: 3, borderRadius: "50%", background: "rgb(163,172,186)" }} />
            <span style={{ fontSize: 12, color: "rgb(106,115,131)" }}>{formatShortDate(tx.date)}</span>
            <span style={{ width: 3, height: 3, borderRadius: "50%", background: "rgb(163,172,186)" }} />
            <span style={{ fontSize: 12, color: "rgb(106,115,131)" }}>via {tx.erp}</span>
          </div>
        </div>

        {/* Body */}
        <div style={{ flex: 1, overflowY: "auto", padding: 20, display: "flex", flexDirection: "column", gap: 18 }}>
          {/* Amount banner */}
          <div style={{
            padding: 16, borderRadius: 10,
            background: `${flowColor(ty.flow)}0F`,
            border: `1px solid ${flowColor(ty.flow)}33`,
            display: "flex", alignItems: "center", justifyContent: "space-between"
          }}>
            <div>
              <div style={{ fontSize: 11, color: "rgb(106,115,131)", fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em" }}>{ty.flow === "revenue" ? "Revenue" : ty.flow === "cost" ? "Cost" : ty.flow === "commit" ? "Commitment" : "Amount"}</div>
              <div style={{ fontSize: 28, fontWeight: 700, fontVariantNumeric: "tabular-nums", letterSpacing: "-.02em", color: flowColor(ty.flow), marginTop: 2 }}>
                {flowSign(ty.flow)}{fmtMoney(tx.amount)}
              </div>
            </div>
            <Icon name={ty.flow === "revenue" ? "trending" : ty.flow === "cost" ? "trendingDown" : "dollar"} size={36} color={flowColor(ty.flow)} style={{ opacity: 0.4 }} />
          </div>

          {/* Detail grid */}
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
            <DetailField label="Vendor / Customer" value={tx.party} icon="briefcase" />
            <DetailField label="Project Dimension" value={`P-2401`} mono />
            <DetailField label="Scope of Work" value={tx.scope || "Unallocated"} />
            <DetailField label="Created By" value={tx.by.name} avatar={tx.by} />
            <DetailField label="Posted Date" value={formatShortDate(tx.date)} />
            <DetailField label="Last Updated" value={tx.updated} />
          </div>

          {/* Description */}
          <div>
            <div style={{ fontSize: 11, color: "rgb(106,115,131)", fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em", marginBottom: 6 }}>Description</div>
            <div style={{ fontSize: 13, color: "rgb(26,27,37)", lineHeight: 1.5, padding: 12, background: "rgb(252,252,253)", border: "1px solid rgb(239,240,242)", borderRadius: 8 }}>
              {tx.description}
            </div>
          </div>

          {/* Line items */}
          {lineItems.length > 0 && (
            <div>
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 8 }}>
                <span style={{ fontSize: 11, color: "rgb(106,115,131)", fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em" }}>Line items ({lineItems.length})</span>
              </div>
              <div style={{ border: "1px solid rgb(239,240,242)", borderRadius: 8, overflow: "hidden" }}>
                {lineItems.map((li, i) => (
                  <div key={i} style={{
                    display: "grid", gridTemplateColumns: "1fr 60px 90px 100px",
                    padding: "10px 12px", gap: 8, alignItems: "center", fontSize: 12,
                    borderBottom: i < lineItems.length - 1 ? "1px solid rgb(239,240,242)" : "none"
                  }}>
                    <span style={{ color: "rgb(26,27,37)" }}>{li.desc}</span>
                    <span style={{ color: "rgb(106,115,131)", textAlign: "right", fontVariantNumeric: "tabular-nums" }}>{li.qty}</span>
                    <span style={{ color: "rgb(106,115,131)", textAlign: "right", fontVariantNumeric: "tabular-nums" }}>{fmtMoney(li.unit)}</span>
                    <span style={{ color: "rgb(26,27,37)", textAlign: "right", fontVariantNumeric: "tabular-nums", fontWeight: 600 }}>{fmtMoney(li.total)}</span>
                  </div>
                ))}
              </div>
            </div>
          )}

          {/* Linked records */}
          <div>
            <div style={{ fontSize: 11, color: "rgb(106,115,131)", fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em", marginBottom: 8 }}>Linked records</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
              {linkedFor(tx).map((l, i) => (
                <button key={i} style={{
                  display: "flex", alignItems: "center", gap: 10, padding: "10px 12px",
                  background: "#fff", border: "1px solid rgb(231,233,236)", borderRadius: 8,
                  cursor: "pointer", fontFamily: "inherit", textAlign: "left", width: "100%"
                }}>
                  <div style={{
                    width: 26, height: 26, borderRadius: 6,
                    background: `${TX_TYPES[l.type]?.color || "#534AFF"}1A`,
                    display: "flex", alignItems: "center", justifyContent: "center"
                  }}>
                    <Icon name={TX_TYPES[l.type]?.icon || "link"} size={12} color={TX_TYPES[l.type]?.color || "#534AFF"} />
                  </div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 12, fontWeight: 500, fontFamily: "ui-monospace, SF Mono, monospace" }}>{l.id}</div>
                    <div style={{ fontSize: 11, color: "rgb(106,115,131)" }}>{l.label}</div>
                  </div>
                  <Icon name="chevronRight" size={14} color="rgb(163,172,186)" />
                </button>
              ))}
            </div>
          </div>

          {/* Activity timeline */}
          <div>
            <div style={{ fontSize: 11, color: "rgb(106,115,131)", fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em", marginBottom: 10 }}>Activity</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
              {timeline.map((ev, i) => (
                <div key={i} style={{ display: "flex", gap: 10 }}>
                  <div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
                    <div style={{ width: 8, height: 8, borderRadius: "50%", background: ev.color, marginTop: 6, flexShrink: 0 }} />
                    {i < timeline.length - 1 && <div style={{ width: 1, flex: 1, background: "rgb(231,233,236)", marginTop: 4 }} />}
                  </div>
                  <div style={{ paddingBottom: i < timeline.length - 1 ? 14 : 0, fontSize: 12, flex: 1 }}>
                    <div style={{ color: "rgb(26,27,37)" }}>{ev.text}</div>
                    <div style={{ color: "rgb(106,115,131)", marginTop: 2 }}>{ev.when}</div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>

        {/* Footer */}
        <div style={{
          display: "flex", alignItems: "center", justifyContent: "space-between",
          padding: "12px 20px", borderTop: "1px solid rgb(239,240,242)", background: "rgb(252,252,253)"
        }}>
          <div style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 11, color: "rgb(106,115,131)" }}>
            <Icon name="link" size={11} />
            Synced from {tx.erp}
          </div>
          <div style={{ display: "flex", gap: 6 }}>
            <Button size="sm" kind="ghost" icon="paperclip">Attach</Button>
            <Button size="sm" kind="primary" icon="link">View Full Record</Button>
          </div>
        </div>
      </div>
    </div>
  );
};

const DetailField = ({ label, value, icon, mono, avatar }) => (
  <div>
    <div style={{ fontSize: 11, color: "rgb(106,115,131)", fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em", marginBottom: 4 }}>{label}</div>
    <div style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 13, color: "rgb(26,27,37)" }}>
      {avatar && <Avatar size={18} initials={avatar.initials} color={avatar.color} />}
      {icon && !avatar && <Icon name={icon} size={12} color="rgb(106,115,131)" />}
      <span style={mono ? { fontFamily: "ui-monospace, SF Mono, monospace", fontSize: 12, padding: "1px 6px", background: "rgb(241,242,244)", borderRadius: 4 } : {}}>{value}</span>
    </div>
  </div>
);

const mockLineItems = (tx) => {
  if (tx.type === "po" && tx.id === "PO-3318") return [
    { desc: "Bifacial Module 580W (Lot 3)", qty: "8,400", unit: 102, total: 856_800 },
    { desc: "Freight + handling",            qty: "1",     unit: 35_600, total: 35_600 },
  ];
  if (tx.type === "invoice" && tx.id === "INV-2026-0148") return [
    { desc: "PV-100 Foundations — 92% complete", qty: "1", unit: 198_000, total: 198_000 },
    { desc: "PV-200 Modules — 64% complete",     qty: "1", unit: 286_000, total: 286_000 },
    { desc: "PV-300 Tracker Install — 38%",       qty: "1", unit: 158_000, total: 158_000 },
  ];
  if (tx.type === "bill" && tx.id === "BILL-9421") return [
    { desc: "Pile-driving labor — Crew A (392 hrs)", qty: "392", unit: 78, total: 30_576 },
    { desc: "Pile-driving labor — Crew B (408 hrs)", qty: "408", unit: 78, total: 31_824 },
    { desc: "Equipment + consumables",                qty: "1",   unit: 85_800, total: 85_800 },
  ];
  if (tx.type === "labor") return [
    { desc: "Foundations crew", qty: "624", unit: 76, total: 47_424 },
    { desc: "Tracker crew",     qty: "320", unit: 84, total: 26_880 },
    { desc: "Electrical crew",  qty: "240", unit: 64, total: 15_360 },
  ];
  return [];
};

const linkedFor = (tx) => {
  if (tx.type === "po") return [
    { type: "bill",    id: "BILL-9421",    label: "Vendor bill — partial receipt" },
    { type: "receipt", id: "GR-5021",      label: "Goods receipt — Reel 14" },
  ];
  if (tx.type === "invoice") return [
    { type: "salesOrder", id: "SO-2210",       label: "Master sales order" },
    { type: "paymentRcv", id: "PMT-7741",      label: "ACH payment — cleared" },
  ];
  if (tx.type === "bill") return [
    { type: "po",        id: "PO-3304",       label: "Originating purchase order" },
    { type: "vendorPmt", id: "VP-6612",       label: "Vendor payment scheduled" },
  ];
  if (tx.type === "labor") return [
    { type: "journal", id: "JE-1108",  label: "Cost reclass to CO-013" },
  ];
  return [
    { type: "salesOrder", id: "SO-2210", label: "Master sales order" },
  ];
};

const mockTimeline = (tx) => [
  { color: "rgb(83,74,255)", text: <><strong>{tx.by.name}</strong> created the transaction</>, when: tx.updated },
  { color: "rgb(34,134,58)", text: <>Synced from <strong>{tx.erp}</strong></>, when: tx.updated },
  { color: "rgb(228,182,68)", text: <>Tagged to project <strong>P-2401</strong> via dimension</>, when: tx.updated },
  { color: "rgb(163,172,186)", text: <>Status set to <strong>{tx.status}</strong></>, when: tx.updated },
];

window.ERPTransactionsTab = ERPTransactionsTab;
