const { useState: useSt, useEffect: useEf, useMemo: useMm } = React;

// ── Shared modal shell — used by both the batch and single mark-as-paid dialogs.
// Pure presentation: header/body/footer wrapper, no business logic.
const Modal = ({ title, onClose, children, footer, width = 400 }) => (
  <div
    style={{ position: "fixed", inset: 0, zIndex: 100, background: "rgba(0,0,0,0.45)", display: "flex", alignItems: "center", justifyContent: "center" }}
    onClick={e => { if (e.target === e.currentTarget) onClose(); }}
  >
    <div className="panel" style={{ width, maxWidth: "calc(100vw - 32px)", boxShadow: "0 8px 32px rgba(0,0,0,0.18)" }}>
      <div className="panel-h">
        <span style={{ fontWeight: 600, fontSize: 14, color: "var(--ink)" }}>{title}</span>
        <button className="icon-btn" onClick={onClose} style={{ marginLeft: "auto", fontSize: 16, lineHeight: 1 }}>×</button>
      </div>
      <div style={{ padding: 16 }}>{children}</div>
      {footer && <div style={{ padding: "12px 16px", borderTop: "1px solid var(--hairline)", display: "flex", gap: 8, justifyContent: "flex-end" }}>{footer}</div>}
    </div>
  </div>
);

// ── Shared receipt-upload dropzone — used by both mark-as-paid dialogs.
const UploadArea = ({ file, preview, onChange, onRemove }) => (
  <div style={{ marginBottom: 4 }}>
    <div style={{ fontSize: 12, fontWeight: 500, color: "var(--ink-2)", marginBottom: 6 }}>
      Payment receipt <span style={{ color: "var(--ink-4)", fontWeight: 400 }}>(optional)</span>
    </div>
    <label style={{
      display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center",
      gap: 6, border: "1.5px dashed var(--hairline)", borderRadius: 7,
      padding: "14px 12px", cursor: "pointer", background: file ? "var(--surface-2)" : "transparent",
    }}>
      <input type="file" accept="image/jpeg,image/png,image/webp,application/pdf" style={{ display: "none" }} onChange={onChange}/>
      {preview ? (
        file.type === "application/pdf"
          ? <div style={{ fontSize: 12, color: "var(--ink-2)" }}>📄 {file.name}</div>
          : <img src={preview} alt="receipt preview" style={{ maxHeight: 120, maxWidth: "100%", borderRadius: 5, objectFit: "contain" }}/>
      ) : (
        <>
          <div style={{ fontSize: 20, color: "var(--ink-4)" }}>↑</div>
          <div style={{ fontSize: 12, color: "var(--ink-3)" }}>Click to upload · JPG, PNG, PDF · max 10 MB</div>
        </>
      )}
    </label>
    {file && (
      <button onClick={onRemove} className="btn ghost" style={{ marginTop: 6, height: 22, padding: "0 6px", fontSize: 11, color: "var(--neg)" }}>
        Remove file
      </button>
    )}
  </div>
);

// ── Segmented control — replaces the hand-rolled sale/delivery + pending/paid toggles.
const Seg = ({ options, value, onChange }) => (
  <div style={{ display: "flex", border: "1px solid var(--hairline)", borderRadius: 5, overflow: "hidden" }}>
    {options.map((opt, i) => (
      <button
        key={opt.value}
        onClick={() => onChange(opt.value)}
        style={{
          padding: "5px 12px", fontSize: 12, fontFamily: "var(--font-sans)", textTransform: "capitalize",
          background: value === opt.value ? "var(--ink)" : "var(--surface)",
          color: value === opt.value ? "var(--paper)" : "var(--ink-3)",
          border: "none", cursor: "pointer",
          borderRight: i < options.length - 1 ? "1px solid var(--hairline)" : "none",
        }}
      >
        {opt.label}
      </button>
    ))}
  </div>
);

// ─────────────────────────────────────────────────────────────────────────────
// Finance page — Settlement section
// Tabs: Settlement | Transactions | Refunds (stubs for next sections)
// ─────────────────────────────────────────────────────────────────────────────

const FinancePage = () => {
  const D  = window.PipalData;
  const I  = window.Icons;
  const sb = window.supabaseClient;

  const [tab, setTab] = useSt("overview");
  const [openAlertCount, setOpenAlertCount] = useSt(0);

  const refreshAlertCount = () => {
    if (!sb) return;
    sb.from("finance_reconciliation_flags")
      .select("id", { count: "exact", head: true })
      .is("resolved_at", null)
      .then(({ count }) => setOpenAlertCount(count || 0));
  };

  useEf(() => { refreshAlertCount(); }, []);

  return (
    <div className="page" data-screen-label="Finance">
      <div className="page-h">
        <div>
          <div className="ts">Money & Insight · Finance</div>
          <h1>Finance</h1>
        </div>
      </div>

      <div className="ftabs" style={{ marginBottom: 18 }}>
        {[
          { id: "overview",     label: "Overview" },
          { id: "settlement",   label: "Settlement" },
          { id: "transactions", label: "Transactions" },
          { id: "refunds",      label: "Refunds" },
          { id: "alerts",       label: "Alerts" },
        ].map(t => (
          <div key={t.id} className={"ftab" + (tab === t.id ? " active" : "")} onClick={() => setTab(t.id)}>
            {t.label}
            {t.id === "alerts" && openAlertCount > 0 && (
              <span className="chip dot neg" style={{ marginLeft: 6, fontSize: 10 }}>{openAlertCount}</span>
            )}
          </div>
        ))}
      </div>

      {tab === "overview"     && <OverviewSection D={D} I={I} sb={sb}/>}
      {tab === "settlement"   && <SettlementSection D={D} I={I} sb={sb}/>}
      {tab === "transactions" && <TransactionsSection D={D} I={I} sb={sb}/>}
      {tab === "refunds"      && <RefundsSection D={D} I={I} sb={sb}/>}
      {tab === "alerts"       && <AlertsSection D={D} I={I} sb={sb} onChange={refreshAlertCount}/>}
    </div>
  );
};

// ─────────────────────────────────────────────────────────────────────────────
// Overview — GMV, order funnel, money flow
// ─────────────────────────────────────────────────────────────────────────────

const OverviewSection = ({ D, I, sb }) => {
  const [orders,  setOrders]  = useSt([]);
  const [payouts, setPayouts] = useSt([]);
  const [returns, setReturns] = useSt([]);
  const [loading, setLoading] = useSt(true);

  useEf(() => {
    if (!sb) return;
    setLoading(true);
    Promise.all([
      sb.from("orders")
        .select("id, order_status, payment_status, payment_method, total_amount, subtotal, tax_amount, delivery_fee, platform_fee_amount, seller_payout_amount, driver_payout_amount, platform_subsidy_amount, coupon_discount_amount, mana_discount_amount, commission_rate, created_at, delivery_method")
        .order("created_at", { ascending: false })
        .limit(1000),
      sb.from("payouts")
        .select("id, type, status, net_amount, gross_amount, created_at"),
      sb.from("order_returns")
        .select("id, status, refund_amount, created_at"),
    ]).then(([{ data: o }, { data: p }, { data: r }]) => {
      setOrders(o || []);
      setPayouts(p || []);
      setReturns(r || []);
      setLoading(false);
    });
  }, []);

  const kpis = useMm(() => {
    const paid = orders.filter(o => o.payment_status === "paid");
    const gmv  = paid.reduce((s, o) => s + Number(o.total_amount || 0), 0);
    const platformFees = paid.reduce((s, o) => s + Number(o.platform_fee_amount || 0), 0);
    const subsidies    = paid.reduce((s, o) => s + Number(o.platform_subsidy_amount || 0), 0);
    const coupons      = paid.reduce((s, o) => s + Number(o.coupon_discount_amount || 0), 0);
    const manaDisc     = paid.reduce((s, o) => s + Number(o.mana_discount_amount || 0), 0);
    const sellerOwed   = payouts.filter(p => p.type === "sale"     && p.status === "pending").reduce((s, p) => s + Number(p.net_amount || 0), 0);
    const driverOwed   = payouts.filter(p => p.type === "delivery" && p.status === "pending").reduce((s, p) => s + Number(p.net_amount || 0), 0);
    const refunded     = returns.filter(r => r.status === "refunded").reduce((s, r) => s + Number(r.refund_amount || 0), 0);
    const pendingPayment = orders.filter(o => o.payment_status === "pending" && o.order_status !== "cancelled")
                                 .reduce((s, o) => s + Number(o.total_amount || 0), 0);
    const netRevenue = platformFees - subsidies - manaDisc;
    return { gmv, platformFees, subsidies, coupons, manaDisc, sellerOwed, driverOwed, refunded, pendingPayment, netRevenue };
  }, [orders, payouts, returns]);

  // order funnel by status
  const funnel = useMm(() => {
    const STATUSES = ["pending", "confirmed", "processing", "shipped", "delivered", "cancelled", "return_initiated"];
    return STATUSES.map(s => ({
      status: s,
      count: orders.filter(o => o.order_status === s).length,
      value: orders.filter(o => o.order_status === s).reduce((sum, o) => sum + Number(o.total_amount || 0), 0),
    })).filter(x => x.count > 0);
  }, [orders]);

  // payment method breakdown
  const byMethod = useMm(() => {
    const map = {};
    orders.filter(o => o.payment_status === "paid").forEach(o => {
      const m = o.payment_method || "unknown";
      if (!map[m]) map[m] = { count: 0, total: 0 };
      map[m].count++;
      map[m].total += Number(o.total_amount || 0);
    });
    return Object.entries(map).map(([method, v]) => ({ method, ...v })).sort((a, b) => b.total - a.total);
  }, [orders]);

  // delivery method breakdown (paid orders)
  const byDelivery = useMm(() => {
    const map = {};
    orders.filter(o => o.payment_status === "paid").forEach(o => {
      const m = o.delivery_method || "standard";
      if (!map[m]) map[m] = { count: 0, total: 0, fee: 0 };
      map[m].count++;
      map[m].total += Number(o.total_amount || 0);
      map[m].fee   += Number(o.delivery_fee || 0);
    });
    return Object.entries(map).map(([method, v]) => ({ method, ...v })).sort((a, b) => b.total - a.total);
  }, [orders]);

  const STATUS_CHIP = { pending: "warn", confirmed: "info", processing: "info", shipped: "info", delivered: "pos", cancelled: "neg", return_initiated: "warn" };

  return (
    <>
      {/* Top KPIs */}
      <div className="kpi-grid" style={{ gridTemplateColumns: "repeat(4,1fr)", marginBottom: 18 }}>
        <div className="kpi">
          <div className="lbl">GMV (paid orders)</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.gmv)}</div>
          <div className="sub"><span className="muted">{orders.filter(o => o.payment_status === "paid").length} orders</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Net platform fee earned</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.netRevenue)}</div>
          <div className="sub"><span className="chip pos dot">gross {D.compactCurrency(kpis.platformFees)} − subsidies − mana</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Total owed (sellers + drivers)</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.sellerOwed + kpis.driverOwed)}</div>
          <div className="sub"><span className="chip warn dot">pending settlement</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Pending payment</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.pendingPayment)}</div>
          <div className="sub"><span className="muted">{orders.filter(o => o.payment_status === "pending" && o.order_status !== "cancelled").length} orders awaiting</span></div>
        </div>
      </div>

      <div className="kpi-grid" style={{ gridTemplateColumns: "repeat(4,1fr)", marginBottom: 22 }}>
        <div className="kpi">
          <div className="lbl">Subsidies spent</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.subsidies)}</div>
          <div className="sub"><span className="muted">platform absorbs</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Coupon discounts</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.coupons)}</div>
          <div className="sub"><span className="muted">buyer-facing</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Mana discounts</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.manaDisc)}</div>
          <div className="sub"><span className="muted">points redeemed</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Refunds issued</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.refunded)}</div>
          <div className="sub"><span className="chip neg dot">{returns.filter(r => r.status === "refunded").length} returns</span></div>
        </div>
      </div>

      <div className="mob-stack" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>

        {/* Order funnel */}
        <div className="panel">
          <div className="panel-h"><span>Order funnel</span></div>
          <div className="t-wrap">
            {loading ? (
              <div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>Loading…</div>
            ) : (
              <table className="t">
                <thead>
                  <tr>
                    <th>Status</th>
                    <th style={{ textAlign: "right" }}>Orders</th>
                    <th style={{ textAlign: "right" }}>Value</th>
                  </tr>
                </thead>
                <tbody>
                  {funnel.map(f => (
                    <tr key={f.status}>
                      <td>
                        <span className={"chip dot " + (STATUS_CHIP[f.status] || "warn")}
                          style={{ textTransform: "capitalize" }}>
                          {f.status.replace(/_/g, " ")}
                        </span>
                      </td>
                      <td style={{ textAlign: "right", fontFamily: "var(--font-mono)", fontSize: 12 }}>{f.count}</td>
                      <td className="num" style={{ textAlign: "right" }}>{D.currency(f.value)}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            )}
          </div>
        </div>

        {/* Money flow breakdown */}
        <div className="panel">
          <div className="panel-h"><span>Money flow (paid orders)</span></div>
          <div style={{ padding: "14px" }}>
            {loading ? (
              <div style={{ textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>Loading…</div>
            ) : (
              <>
                <div style={{ marginBottom: 16 }}>
                  <div style={{ fontSize: 10, fontFamily: "var(--font-mono)", color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 8 }}>By payment method</div>
                  {byMethod.map(m => (
                    <div key={m.method} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "4px 0", borderBottom: "1px solid var(--hairline)" }}>
                      <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                        <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, textTransform: "capitalize", color: "var(--ink-2)" }}>{m.method}</span>
                        <span className="muted" style={{ fontSize: 10 }}>{m.count} orders</span>
                      </div>
                      <span className="num" style={{ fontSize: 13, fontWeight: 550 }}>{D.currency(m.total)}</span>
                    </div>
                  ))}
                </div>
                <div>
                  <div style={{ fontSize: 10, fontFamily: "var(--font-mono)", color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 8 }}>By delivery method</div>
                  {byDelivery.map(d => (
                    <div key={d.method} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "4px 0", borderBottom: "1px solid var(--hairline)" }}>
                      <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                        <span className={"chip dot " + (d.method === "flash" ? "warn" : "info")} style={{ fontSize: 10 }}>{d.method}</span>
                        <span className="muted" style={{ fontSize: 10 }}>{d.count} · fees {D.currency(d.fee)}</span>
                      </div>
                      <span className="num" style={{ fontSize: 13, fontWeight: 550 }}>{D.currency(d.total)}</span>
                    </div>
                  ))}
                </div>
              </>
            )}
          </div>
        </div>

      </div>

      {/* Payout summary */}
      <div style={{ marginTop: 14 }}>
        <div className="panel">
          <div className="panel-h"><span>Settlement summary</span></div>
          <div style={{ padding: "14px", display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 14 }}>
            {[
              { label: "Seller payouts pending", val: kpis.sellerOwed, chip: "warn", chipLabel: `${payouts.filter(p=>p.type==="sale"&&p.status==="pending").length} pending` },
              { label: "Driver payouts pending", val: kpis.driverOwed, chip: "warn", chipLabel: `${payouts.filter(p=>p.type==="delivery"&&p.status==="pending").length} pending` },
              { label: "Seller payouts paid", val: payouts.filter(p=>p.type==="sale"&&p.status==="paid").reduce((s,p)=>s+Number(p.net_amount||0),0), chip: "pos", chipLabel: `${payouts.filter(p=>p.type==="sale"&&p.status==="paid").length} paid` },
              { label: "Driver payouts paid", val: payouts.filter(p=>p.type==="delivery"&&p.status==="paid").reduce((s,p)=>s+Number(p.net_amount||0),0), chip: "pos", chipLabel: `${payouts.filter(p=>p.type==="delivery"&&p.status==="paid").length} paid` },
            ].map(s => (
              <div key={s.label} style={{ background: "var(--surface-2)", borderRadius: 7, padding: "12px 14px" }}>
                <div style={{ fontSize: 11, color: "var(--ink-3)", marginBottom: 6 }}>{s.label}</div>
                <div style={{ fontSize: 18, fontWeight: 600, letterSpacing: "-0.02em", color: "var(--ink)", marginBottom: 4 }}>{loading ? "—" : D.compactCurrency(s.val)}</div>
                <span className={"chip dot " + s.chip} style={{ fontSize: 10 }}>{s.chipLabel}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </>
  );
};

// ─────────────────────────────────────────────────────────────────────────────
// Settlement
// ─────────────────────────────────────────────────────────────────────────────

const SettlementSection = ({ D, I, sb }) => {
  const [payouts,  setPayouts]  = useSt([]);
  const [sellers,  setSellers]  = useSt({});   // user_id → { display_name, username, phone }
  const [drivers,  setDrivers]  = useSt({});   // user_id → { display_name, username }
  const [loading,  setLoading]  = useSt(true);
  const [selType,  setSelType]  = useSt("sale");   // "sale" | "delivery"
  const [selStatus,setSelStatus]= useSt("pending");
  const [search,   setSearch]   = useSt("");
  const [selId,    setSelId]    = useSt(null);
  const [marking,    setMarking]    = useSt(false);
  const [selected,   setSelected]   = useSt(new Set());  // payout ids checked for batch pay
  const [batchModal, setBatchModal] = useSt(false);
  const [batchFile,  setBatchFile]  = useSt(null);
  const [batchPrev,  setBatchPrev]  = useSt(null);
  const [batchErr,   setBatchErr]   = useSt(null);

  // ── fetch ────────────────────────────────────────────────────────────────

  useEf(() => {
    if (!sb) return;
    setLoading(true);

    sb.from("payouts")
      .select("id, user_id, amount, type, order_id, delivery_id, status, created_at, paid_at, gross_amount, commission_rate, net_amount, breakdown, notes, payment_receipt_url, orders(order_number, payment_method, payment_status), deliveries(order_id, delivery_tier, is_flash, driver_id, cash_collected, cash_deposited, route_id, routes(id, dispatch_window, dispatched_at, completed_at, total_stops, total_distance_m))")
      .order("created_at", { ascending: false })
      .limit(500)
      .then(async ({ data: rows, error }) => {
        if (error || !rows) { setLoading(false); return; }

        // For driver payouts, order_id may be null on the payout itself but present on the delivery.
        const deliveryOrderIds = rows.map(r => r.deliveries?.order_id).filter(Boolean);
        const { data: deliveryOrders } = deliveryOrderIds.length > 0
          ? await sb.from("orders").select("id, order_number, payment_method, payment_status").in("id", deliveryOrderIds)
          : { data: [] };
        const deliveryOrderMap = (deliveryOrders || []).reduce((m, o) => { m[o.id] = o; return m; }, {});

        const normalised = rows.map(r => {
          const firstEarning  = Array.isArray(r.breakdown?.earnings) ? r.breakdown.earnings[0] : null;
          const delivOrd      = r.deliveries?.order_id ? deliveryOrderMap[r.deliveries.order_id] : null;
          return {
            ...r,
            order_number:   r.orders?.order_number
                         ?? delivOrd?.order_number
                         ?? r.breakdown?.order_number
                         ?? (firstEarning?.order_number ?? null),
            delivery_tier:  r.deliveries?.delivery_tier
                         ?? r.breakdown?.delivery_tier
                         ?? r.breakdown?.delivery_type
                         ?? (firstEarning?.delivery_tier ?? null),
            resolved_order_id: r.order_id ?? r.deliveries?.order_id ?? null,
            payment_method: r.orders?.payment_method ?? delivOrd?.payment_method ?? null,
            payment_status: r.orders?.payment_status ?? delivOrd?.payment_status ?? null,
            driver_id:      r.deliveries?.driver_id ?? null,
            route_id:       r.deliveries?.route_id ?? null,
            route:          r.deliveries?.routes ?? null,
            cash_collected: r.deliveries?.cash_collected != null ? Number(r.deliveries.cash_collected) : null,
            cash_deposited: r.deliveries?.cash_deposited ?? null,
            orders:         undefined,
            deliveries:     undefined,
          };
        });

        // Fetch both seller and driver profiles in one query
        const sellerIds = [...new Set(normalised.map(r => r.user_id).filter(Boolean))];
        const driverIds = [...new Set(normalised.map(r => r.driver_id).filter(Boolean))];
        const allIds    = [...new Set([...sellerIds, ...driverIds])];
        const { data: profiles } = allIds.length > 0
          ? await sb.from("user_profiles").select("id, display_name, username, phone").in("id", allIds)
          : { data: [] };

        const profMap = (profiles || []).reduce((m, p) => { m[p.id] = p; return m; }, {});
        setSellers(profMap);
        setDrivers(profMap);   // same map — drivers are also users
        setPayouts(normalised);
        if (normalised.length > 0) setSelId(normalised[0].id);
        setLoading(false);
      });
  }, []);

  const [expanded,      setExpanded]      = useSt(new Set());   // user_ids expanded
  const [expandedRoutes, setExpandedRoutes] = useSt(new Set()); // route_ids expanded within driver rows

  // ── derived ──────────────────────────────────────────────────────────────

  const filtered = useMm(() => {
    let list = payouts.filter(p => p.type === selType && p.status === selStatus);
    if (search.trim()) {
      const q = search.toLowerCase();
      list = list.filter(p => {
        const prof = sellers[p.user_id];
        return (
          (prof?.display_name || "").toLowerCase().includes(q) ||
          (prof?.username     || "").toLowerCase().includes(q) ||
          (p.order_number     || "").toLowerCase().includes(q) ||
          (p.order_id         || "").toLowerCase().includes(q) ||
          (p.notes            || "").toLowerCase().includes(q)
        );
      });
    }
    return list;
  }, [payouts, selType, selStatus, search, sellers]);

  // Group filtered payouts by user (seller or driver), sorted by total net desc.
  // For driver payouts, sub-group each user's payouts by route_id so the list
  // renders 3 levels: driver → route/dispatch run → individual delivery payout.
  const grouped = useMm(() => {
    const map = {};
    filtered.forEach(p => {
      if (!map[p.user_id]) map[p.user_id] = { user_id: p.user_id, payouts: [] };
      map[p.user_id].payouts.push(p);
    });
    return Object.values(map).map(g => {
      // Build route sub-groups for driver payouts
      const routeMap = {};
      g.payouts.forEach(p => {
        const key = p.route_id || "__no_route__";
        if (!routeMap[key]) routeMap[key] = { route_id: p.route_id || null, route: p.route || null, payouts: [] };
        routeMap[key].payouts.push(p);
      });
      const routes = Object.values(routeMap).map(r => ({
        ...r,
        totalNet:   r.payouts.reduce((s, p) => s + Number(p.net_amount || 0), 0),
        totalGross: r.payouts.reduce((s, p) => s + Number(p.gross_amount || p.amount || 0), 0),
        latest:     r.payouts[0]?.created_at || "",
      })).sort((a, b) => new Date(b.latest) - new Date(a.latest));
      return {
        ...g,
        routes,
        totalNet:   g.payouts.reduce((s, p) => s + Number(p.net_amount || 0), 0),
        totalGross: g.payouts.reduce((s, p) => s + Number(p.gross_amount || p.amount || 0), 0),
        latest:     g.payouts[0]?.created_at || "",
      };
    }).sort((a, b) => b.totalNet - a.totalNet);
  }, [filtered]);

  const allPayoutIds = useMm(() => filtered.map(p => p.id), [filtered]);

  // Look up within `filtered`, not the full `payouts` list — otherwise switching
  // Sellers/Drivers or Pending/Paid keeps showing a detail panel for a payout
  // that no longer matches the active filter (wrong party, wrong status).
  const sel = filtered.find(p => p.id === selId) || null;

  const kpis = useMm(() => {
    const saleP = payouts.filter(p => p.type === "sale"     && p.status === "pending");
    const saleD = payouts.filter(p => p.type === "sale"     && p.status === "paid");
    const delvP = payouts.filter(p => p.type === "delivery" && p.status === "pending");
    return {
      salePendingCount: saleP.length,
      salePendingNet:   saleP.reduce((s, p) => s + Number(p.net_amount || 0), 0),
      salePaidNet:      saleD.reduce((s, p) => s + Number(p.net_amount || 0), 0),
      delvPendingCount: delvP.length,
      delvPendingNet:   delvP.reduce((s, p) => s + Number(p.net_amount || 0), 0),
    };
  }, [payouts]);

  // ── batch pay ────────────────────────────────────────────────────────────

  const toggleSelect = (id) => {
    setSelected(prev => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  };

  const toggleSellerPayouts = (userId) => {
    const ids = grouped.find(g => g.user_id === userId)?.payouts.map(p => p.id) || [];
    const allChecked = ids.every(id => selected.has(id));
    setSelected(prev => {
      const next = new Set(prev);
      if (allChecked) ids.forEach(id => next.delete(id));
      else            ids.forEach(id => next.add(id));
      return next;
    });
  };

  const toggleAll = () => {
    if (selected.size === allPayoutIds.length) {
      setSelected(new Set());
    } else {
      setSelected(new Set(allPayoutIds));
    }
  };

  const toggleExpanded = (userId) => {
    setExpanded(prev => {
      const next = new Set(prev);
      next.has(userId) ? next.delete(userId) : next.add(userId);
      return next;
    });
  };

  const toggleExpandedRoute = (key) => {
    setExpandedRoutes(prev => {
      const next = new Set(prev);
      next.has(key) ? next.delete(key) : next.add(key);
      return next;
    });
  };

  const openBatchModal = () => { setBatchFile(null); setBatchErr(null); setBatchModal(true); };
  const closeBatchModal = () => { setBatchFile(null); setBatchPrev(null); setBatchErr(null); setBatchModal(false); };

  useEf(() => {
    if (!batchFile) { setBatchPrev(null); return; }
    const url = URL.createObjectURL(batchFile);
    setBatchPrev(url);
    return () => URL.revokeObjectURL(url);
  }, [batchFile]);

  const handleMarkPaid = async () => {
    if (selected.size === 0) return;
    setMarking(true);
    setBatchErr(null);
    const ids = [...selected];
    let receiptUrl = null;

    if (batchFile) {
      const ext  = batchFile.name.split(".").pop();
      const path = `batch/${Date.now()}.${ext}`;
      const { error: upErr } = await sb.storage.from("payout-receipts").upload(path, batchFile, { upsert: true });
      if (upErr) { setBatchErr("Upload failed: " + upErr.message); setMarking(false); return; }
      const { data: urlData } = await sb.storage.from("payout-receipts").createSignedUrl(path, 60 * 60 * 24 * 365);
      receiptUrl = urlData?.signedUrl ?? null;
    }

    const update = { status: "paid", paid_at: new Date().toISOString() };
    if (receiptUrl) update.payment_receipt_url = receiptUrl;

    const { error } = await sb.from("payouts").update(update).in("id", ids);
    if (error) {
      setBatchErr("Error: " + error.message);
      setMarking(false);
      return;
    }
    setPayouts(prev => prev.map(p => ids.includes(p.id) ? { ...p, ...update } : p));
    setSelected(new Set());
    if (selStatus === "pending") setSelId(null);
    closeBatchModal();
    setMarking(false);
  };

  const selectedTotal = useMm(() =>
    [...selected].reduce((s, id) => {
      const p = payouts.find(x => x.id === id);
      return s + Number(p?.net_amount || 0);
    }, 0)
  , [selected, payouts]);

  // ── render ────────────────────────────────────────────────────────────────

  return (
    <>
      {/* KPI strip */}
      <div className="kpi-grid" style={{ gridTemplateColumns: "repeat(4,1fr)", marginBottom: 18 }}>
        <div className="kpi">
          <div className="lbl">Seller payouts due</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.salePendingNet)}</div>
          <div className="sub"><span className="chip warn dot">{kpis.salePendingCount} pending</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Driver payouts due</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.delvPendingNet)}</div>
          <div className="sub"><span className="chip warn dot">{kpis.delvPendingCount} pending</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Seller paid (all time)</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.salePaidNet)}</div>
          <div className="sub"><span className="muted">{payouts.filter(p => p.type==="sale" && p.status==="paid").length} payouts</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Total owed</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.salePendingNet + kpis.delvPendingNet)}</div>
          <div className="sub"><span className="muted">sellers + drivers</span></div>
        </div>
      </div>

      {/* Sub-tabs: type + status */}
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 12, flexWrap: "wrap" }}>
        <Seg
          options={[{ value: "sale", label: "Sellers" }, { value: "delivery", label: "Drivers" }]}
          value={selType}
          onChange={t => { setSelType(t); setSelected(new Set()); setSelId(null); }}
        />
        <Seg
          options={[{ value: "pending", label: "Pending" }, { value: "paid", label: "Paid" }]}
          value={selStatus}
          onChange={s => { setSelStatus(s); setSelected(new Set()); setSelId(null); }}
        />
        <div style={{ marginLeft: "auto", display: "flex", gap: 6 }}>
          {selected.size > 0 && selStatus === "pending" && (
            <button
              className="btn primary"
              disabled={marking}
              onClick={openBatchModal}
              style={{ gap: 6 }}
            >
              <I.check size={11}/>
              {marking ? "Marking…" : `Mark paid · ${D.currency(selectedTotal)}`}
            </button>
          )}
          <button className="btn"><I.download size={12}/>Export</button>
        </div>
      </div>

      {/* Main two-panel layout */}
      <div className="mob-stack" style={{ display: "grid", gridTemplateColumns: "1fr 360px", gap: 14, height: "calc(100vh - 420px)", minHeight: 480 }}>

        {/* ── Left: grouped seller/driver list ── */}
        <div className="panel" style={{ display: "flex", flexDirection: "column", overflow: "hidden" }}>
          <div className="panel-h">
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 11 }}>
              {grouped.length} {selType === "sale" ? "sellers" : "drivers"} · {filtered.length} payouts · {selStatus}
            </span>
            {selStatus === "pending" && filtered.length > 0 && (
              <span
                style={{ fontSize: 11, color: "var(--ink-3)", cursor: "pointer", userSelect: "none" }}
                onClick={toggleAll}
              >
                {selected.size === allPayoutIds.length ? "Deselect all" : "Select all"}
              </span>
            )}
            <div className="right" style={{ position: "relative" }}>
              <I.search size={12} style={{ position: "absolute", left: 10, top: "50%", transform: "translateY(-50%)", color: "var(--ink-4)", pointerEvents: "none" }}/>
              <input
                value={search}
                onChange={e => setSearch(e.target.value)}
                placeholder="Search payee, order…"
                style={{
                  paddingLeft: 28, paddingRight: 10, height: 26, width: 200,
                  background: "var(--surface-2)", border: "1px solid var(--hairline)",
                  borderRadius: 5, fontSize: 12, color: "var(--ink)", outline: "none",
                  fontFamily: "var(--font-sans)"
                }}
              />
            </div>
          </div>

          <div style={{ overflow: "auto", flex: 1 }}>
            {loading ? (
              <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>Loading payouts…</div>
            ) : grouped.length === 0 ? (
              <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>No {selStatus} {selType} payouts</div>
            ) : grouped.map(g => {
              const prof        = sellers[g.user_id];
              const name        = prof?.display_name || prof?.username || g.user_id?.slice(0, 8) || "—";
              const isOpen      = expanded.has(g.user_id);
              const sellerIds   = g.payouts.map(p => p.id);
              const checkedCount = sellerIds.filter(id => selected.has(id)).length;
              const allChecked  = sellerIds.length > 0 && checkedCount === sellerIds.length;
              const someChecked = checkedCount > 0 && !allChecked;

              return (
                <div key={g.user_id} style={{ borderBottom: "1px solid var(--hairline)" }}>
                  {/* Seller header row */}
                  <div
                    style={{
                      display: "flex", alignItems: "center", gap: 10,
                      padding: "9px 14px", cursor: "pointer",
                      background: isOpen ? "var(--surface-2)" : undefined,
                    }}
                    onClick={() => toggleExpanded(g.user_id)}
                  >
                    {selStatus === "pending" && (
                      <div onClick={e => { e.stopPropagation(); toggleSellerPayouts(g.user_id); }}
                        style={{ flexShrink: 0, width: 16, height: 16, position: "relative", cursor: "pointer" }}>
                        <input
                          type="checkbox"
                          checked={allChecked}
                          ref={el => { if (el) el.indeterminate = someChecked; }}
                          onChange={() => toggleSellerPayouts(g.user_id)}
                          style={{ cursor: "pointer", width: 14, height: 14 }}
                          onClick={e => e.stopPropagation()}
                        />
                      </div>
                    )}
                    <div className="avatar" style={{ width: 26, height: 26, fontSize: 10, flexShrink: 0 }}>
                      {(name[0] || "?").toUpperCase()}
                    </div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontWeight: 500, fontSize: 13, color: "var(--ink)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{name}</div>
                      {prof?.phone && <div style={{ fontSize: 10, color: "var(--ink-4)", fontFamily: "var(--font-mono)" }}>{prof.phone}</div>}
                    </div>
                    <div style={{ textAlign: "right", flexShrink: 0 }}>
                      <div style={{ fontFamily: "var(--font-mono)", fontSize: 13, fontWeight: 600, color: "var(--ink)" }}>{D.currency(g.totalNet)}</div>
                      <div style={{ fontSize: 10, color: "var(--ink-3)" }}>
                        {g.payouts.length} payout{g.payouts.length > 1 ? "s" : ""}
                        {checkedCount > 0 && <span style={{ color: "var(--accent-ink)", marginLeft: 4 }}>· {checkedCount} selected</span>}
                      </div>
                    </div>
                    <div style={{ color: "var(--ink-4)", fontSize: 11, flexShrink: 0, marginLeft: 4 }}>
                      {isOpen ? "▲" : "▼"}
                    </div>
                  </div>

                  {/* Expanded: for sellers = flat payout list; for drivers = route → delivery nesting */}
                  {isOpen && (
                    <div style={{ background: "var(--surface-2)" }}>
                      {selType === "sale" ? (
                        // ── Seller: flat payout list ──────────────────────────────
                        g.payouts.map((p, i) => <PayoutRow key={p.id} p={p} i={i} selId={selId} setSelId={setSelId} selStatus={selStatus} selected={selected} toggleSelect={toggleSelect} drivers={drivers} D={D} indent={44}/>)
                      ) : (
                        // ── Driver: route → delivery nesting ─────────────────────
                        g.routes.map((rt, ri) => {
                          const routeKey   = `${g.user_id}__${rt.route_id || ri}`;
                          const rtOpen     = expandedRoutes.has(routeKey);
                          const rtChecked  = rt.payouts.every(p => selected.has(p.id));
                          const rtSome     = rt.payouts.some(p => selected.has(p.id)) && !rtChecked;
                          const toggleRtPayouts = (e) => {
                            e.stopPropagation();
                            const ids = rt.payouts.map(p => p.id);
                            const allChk = ids.every(id => selected.has(id));
                            setSelected(prev => {
                              const next = new Set(prev);
                              if (allChk) ids.forEach(id => next.delete(id));
                              else        ids.forEach(id => next.add(id));
                              return next;
                            });
                          };
                          // Route label: window + date
                          const rtDate = rt.route?.dispatched_at || rt.latest;
                          const rtDateStr = rtDate ? new Date(rtDate).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "—";
                          const rtWindow  = rt.route?.dispatch_window || null;
                          const rtDist    = rt.route?.total_distance_m ? `${(rt.route.total_distance_m / 1000).toFixed(1)} km` : null;
                          return (
                            <div key={routeKey} style={{ borderTop: ri === 0 ? "1px solid var(--hairline)" : "1px solid color-mix(in srgb, var(--hairline) 50%, transparent)" }}>
                              {/* Route header row */}
                              <div
                                onClick={() => toggleExpandedRoute(routeKey)}
                                style={{ display: "flex", alignItems: "center", gap: 8, padding: "7px 14px 7px 44px", cursor: "pointer", background: rtOpen ? "color-mix(in srgb, var(--hairline) 40%, var(--surface-2))" : undefined }}
                              >
                                {selStatus === "pending" && (
                                  <div onClick={toggleRtPayouts} style={{ flexShrink: 0 }}>
                                    <input type="checkbox" checked={rtChecked} ref={el => { if (el) el.indeterminate = rtSome; }}
                                      onChange={toggleRtPayouts} style={{ cursor: "pointer", width: 12, height: 12 }}
                                      onClick={e => e.stopPropagation()}/>
                                  </div>
                                )}
                                <div style={{ flex: 1, minWidth: 0 }}>
                                  <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                                    {rt.route_id
                                      ? <window.EntityLink type="delivery" id={rt.route_id} label={rt.route_id.slice(0, 8).toUpperCase()} style={{ fontSize: 11 }}/>
                                      : <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--ink-2)" }}>No route</span>}
                                    {rtWindow && <span className="chip info" style={{ fontSize: 9 }}>{rtWindow}</span>}
                                    {rtDist   && <span style={{ fontSize: 10, color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>{rtDist}</span>}
                                  </div>
                                  <div style={{ fontSize: 10, color: "var(--ink-4)", marginTop: 1 }}>
                                    {rt.payouts.length} order{rt.payouts.length > 1 ? "s" : ""} · {rtDateStr}
                                  </div>
                                </div>
                                <div style={{ fontFamily: "var(--font-mono)", fontSize: 12, fontWeight: 600, color: "var(--ink)", flexShrink: 0 }}>{D.currency(rt.totalNet)}</div>
                                <div style={{ color: "var(--ink-4)", fontSize: 10, flexShrink: 0, marginLeft: 2 }}>{rtOpen ? "▲" : "▼"}</div>
                              </div>
                              {/* Delivery/order rows within route */}
                              {rtOpen && (
                                <div style={{ background: "color-mix(in srgb, var(--surface-3) 60%, var(--surface-2))" }}>
                                  {rt.payouts.map((p, i) => <PayoutRow key={p.id} p={p} i={i} selId={selId} setSelId={setSelId} selStatus={selStatus} selected={selected} toggleSelect={toggleSelect} drivers={drivers} D={D} indent={60}/>)}
                                </div>
                              )}
                            </div>
                          );
                        })
                      )}
                      {/* Per-payee subtotal footer */}
                      <div style={{ display: "flex", justifyContent: "space-between", padding: "6px 14px 6px 44px", borderTop: "1px solid var(--hairline)" }}>
                        <span style={{ fontSize: 11, color: "var(--ink-4)", fontFamily: "var(--font-mono)" }}>
                          {selType === "delivery"
                            ? `${g.routes.length} route${g.routes.length > 1 ? "s" : ""} · ${g.payouts.length} deliveries · gross ${D.currency(g.totalGross)}`
                            : `${g.payouts.length} payouts · gross ${D.currency(g.totalGross)}`}
                        </span>
                        <span style={{ fontSize: 11, fontFamily: "var(--font-mono)", fontWeight: 600, color: "var(--ink)" }}>
                          Net {D.currency(g.totalNet)}
                        </span>
                      </div>
                    </div>
                  )}
                </div>
              );
            })}
          </div>

          {/* Footer totals */}
          {!loading && filtered.length > 0 && (
            <div style={{ padding: "8px 14px", borderTop: "1px solid var(--hairline)", display: "flex", gap: 20, alignItems: "center" }}>
              <span className="muted" style={{ fontSize: 11, fontFamily: "var(--font-mono)" }}>{grouped.length} payees · {filtered.length} payouts</span>
              <span style={{ fontSize: 11, fontFamily: "var(--font-mono)", color: "var(--ink-2)" }}>
                Total net: <strong style={{ color: "var(--ink)" }}>{D.currency(filtered.reduce((s, p) => s + Number(p.net_amount || 0), 0))}</strong>
              </span>
              {selected.size > 0 && (
                <span style={{ fontSize: 11, fontFamily: "var(--font-mono)", color: "var(--accent-ink)" }}>
                  Selected: <strong>{D.currency(selectedTotal)}</strong> ({selected.size})
                </span>
              )}
            </div>
          )}
        </div>

        {/* ── Right: payout detail ── */}
        <div className="panel" style={{ display: "flex", flexDirection: "column", overflow: "hidden" }}>
          {!sel ? (
            <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--ink-3)", fontSize: 12 }}>
              Select a payout
            </div>
          ) : (
            <PayoutDetail payout={sel} sellers={sellers} drivers={drivers} D={D} I={I} sb={sb}
              onMarkPaid={(id, receiptUrl) => {
                setPayouts(prev => prev.map(p => p.id === id
                  ? { ...p, status: "paid", paid_at: new Date().toISOString(), ...(receiptUrl ? { payment_receipt_url: receiptUrl } : {}) }
                  : p
                ));
              }}
            />
          )}
        </div>

      </div>

      {/* Batch mark-paid modal */}
      {batchModal && (
        <Modal
          title={`Mark ${selected.size} payout${selected.size > 1 ? "s" : ""} as paid`}
          onClose={closeBatchModal}
          footer={<>
            <button className="btn" onClick={closeBatchModal} disabled={marking}>Cancel</button>
            <button className="btn primary" onClick={handleMarkPaid} disabled={marking}>
              <I.check size={11}/>
              {marking ? "Saving…" : `Confirm · ${D.currency(selectedTotal)}`}
            </button>
          </>}
        >
          <div style={{ background: "var(--surface-2)", borderRadius: 7, padding: "10px 12px", marginBottom: 16 }}>
            <div style={{ fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--font-mono)", marginBottom: 4 }}>
              {selType === "sale" ? "Seller" : "Driver"} payouts · {selStatus}
            </div>
            <div style={{ fontSize: 20, fontWeight: 600, color: "var(--ink)", letterSpacing: "-0.02em" }}>{D.currency(selectedTotal)}</div>
            <div style={{ fontSize: 12, color: "var(--ink-3)", marginTop: 2 }}>{selected.size} payouts selected</div>
          </div>
          <UploadArea
            file={batchFile}
            preview={batchPrev}
            onChange={e => { const f = e.target.files?.[0]; if (f) { setBatchFile(f); setBatchErr(null); } }}
            onRemove={() => setBatchFile(null)}
          />
          {batchErr && <div style={{ fontSize: 12, color: "var(--neg)", marginTop: 8 }}>{batchErr}</div>}
        </Modal>
      )}
    </>
  );
};

// ── Reusable payout row (used in both seller flat list and driver delivery list) ──

const PayoutRow = ({ p, i, selId, setSelId, selStatus, selected, toggleSelect, drivers, D, indent = 44 }) => {
  const gross      = Number(p.gross_amount || p.amount || 0);
  const net        = Number(p.net_amount   || p.amount || 0);
  const rate       = p.commission_rate != null ? `${(Number(p.commission_rate) * 100).toFixed(1)}%` : null;
  const dateStr    = p.created_at ? new Date(p.created_at).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "—";
  const paidStr    = p.paid_at    ? new Date(p.paid_at).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : null;
  const isChecked  = selected.has(p.id);
  const isActive   = selId === p.id;
  const isCash     = p.payment_method === "cash";
  const driverProf = p.driver_id ? drivers[p.driver_id] : null;
  const driverName = driverProf?.display_name || driverProf?.username || (p.driver_id ? "Driver" : null);
  const cashStatus = isCash
    ? p.cash_deposited
      ? { label: "Deposited",   color: "var(--pos)",    bg: "color-mix(in srgb, var(--pos) 12%, transparent)" }
      : (p.cash_collected && p.cash_collected > 0)
        ? { label: "With driver", color: "#d97706",       bg: "color-mix(in srgb, #d97706 12%, transparent)" }
        : { label: "Uncollected", color: "var(--ink-3)",  bg: "var(--surface-3)" }
    : null;

  return (
    <div
      key={p.id}
      onClick={() => setSelId(p.id)}
      style={{
        display: "flex", alignItems: "flex-start", gap: 10,
        padding: `10px 14px 10px ${indent}px`,
        cursor: "pointer",
        background: isActive ? "color-mix(in srgb, var(--accent) 8%, var(--surface-2))" : undefined,
        borderTop: i === 0 ? "1px solid var(--hairline)" : "1px solid color-mix(in srgb, var(--hairline) 60%, transparent)",
        borderLeft: isActive ? "2px solid var(--accent)" : "2px solid transparent",
      }}
    >
      {selStatus === "pending" && (
        <div onClick={e => { e.stopPropagation(); toggleSelect(p.id); }} style={{ flexShrink: 0, paddingTop: 2 }}>
          <input type="checkbox" checked={isChecked} onChange={() => toggleSelect(p.id)}
            style={{ cursor: "pointer", width: 13, height: 13 }}
            onClick={e => e.stopPropagation()}/>
        </div>
      )}
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 5 }}>
          {p.resolved_order_id
            ? <window.EntityLink type="order" id={p.resolved_order_id} label={p.order_number || p.id.slice(0, 8).toUpperCase()} style={{ fontSize: 12, letterSpacing: "0.02em" }} />
            : <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, fontWeight: 600, color: "var(--ink)", letterSpacing: "0.02em" }}>
                {p.order_number || p.id.slice(0, 8).toUpperCase()}
              </span>}
          {p.delivery_tier && (
            <span className={"chip dot " + (p.delivery_tier === "flash" ? "warn" : "info")} style={{ fontSize: 9 }}>
              {p.delivery_tier}
            </span>
          )}
          <span style={{ fontSize: 10, color: "var(--ink-3)", marginLeft: "auto" }}>
            {paidStr ? `paid ${paidStr}` : dateStr}
          </span>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
          {p.payment_method && (() => {
            const pm = p.payment_method;
            const pmStyle = pm === "cash"
              ? { color: "#92400e", background: "#fef3c7", border: "1px solid #fde68a" }
              : pm === "wallet"
                ? { color: "#1e40af", background: "#eff6ff", border: "1px solid #bfdbfe" }
                : { color: "#065f46", background: "#ecfdf5", border: "1px solid #a7f3d0" };
            return <span style={{ fontSize: 10, fontWeight: 600, padding: "1px 6px", borderRadius: 4, fontFamily: "var(--font-mono)", textTransform: "uppercase", letterSpacing: "0.04em", ...pmStyle }}>{pm}</span>;
          })()}
          {driverName && (
            <span style={{ fontSize: 11, color: "var(--ink-2)", display: "flex", alignItems: "center", gap: 3 }}>
              <span style={{ color: "var(--ink-4)" }}>↑</span>
              <span style={{ fontWeight: 500 }}>{driverName}</span>
              {driverProf?.phone && <span style={{ color: "var(--ink-3)", fontFamily: "var(--font-mono)", fontSize: 10 }}>{driverProf.phone}</span>}
            </span>
          )}
          {cashStatus && (
            <span style={{ fontSize: 10, fontWeight: 600, padding: "1px 7px", borderRadius: 10, color: cashStatus.color, background: cashStatus.bg, letterSpacing: "0.02em" }}>
              {cashStatus.label}
              {cashStatus.label === "With driver" && p.cash_collected ? ` · ${D.currency(p.cash_collected)}` : ""}
            </span>
          )}
          {rate && (
            <span style={{ fontSize: 10, color: "var(--ink-3)", marginLeft: "auto", fontFamily: "var(--font-mono)" }}>
              {rate} · gross {D.currency(gross)}
            </span>
          )}
        </div>
      </div>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 14, fontWeight: 700, color: "var(--ink)", flexShrink: 0, paddingTop: 1 }}>
        {D.currency(net)}
      </div>
    </div>
  );
};

// ── Payout detail panel ────────────────────────────────────────────────────────

const PayoutDetail = ({ payout: p, sellers, D, I, sb, onMarkPaid }) => {
  const prof = sellers[p.user_id];
  const name = prof?.display_name || prof?.username || "Unknown";
  const gross = Number(p.gross_amount || p.amount || 0);
  const net   = Number(p.net_amount   || p.amount || 0);
  const rate  = p.commission_rate != null ? `${(Number(p.commission_rate) * 100).toFixed(1)}%` : null;
  const [acting,   setActing]   = useSt(false);
  const [order,    setOrder]    = useSt(null);
  const [loadOrd,  setLoadOrd]  = useSt(false);
  const [showModal,setShowModal]= useSt(false);
  const [file,     setFile]     = useSt(null);       // File object
  const [preview,  setPreview]  = useSt(null);       // object URL for preview
  const [uploading,setUploading]= useSt(false);
  const [uploadErr,setUploadErr]= useSt(null);

  // Fetch order receipt snapshot whenever a sale payout is selected
  useEf(() => {
    if (!p.resolved_order_id || !sb) return;
    setOrder(null);
    setLoadOrd(true);
    sb.rpc("get_order_receipt", { p_order_id: p.resolved_order_id })
      .then(({ data }) => { setOrder(data && data.status !== "pending" && data.status !== "error" ? data : null); setLoadOrd(false); });
  }, [p.id]);

  // Revoke object URL when file changes or modal closes
  useEf(() => {
    if (!file) { setPreview(null); return; }
    const url = URL.createObjectURL(file);
    setPreview(url);
    return () => URL.revokeObjectURL(url);
  }, [file]);

  const openModal = () => { setFile(null); setUploadErr(null); setShowModal(true); };
  const closeModal = () => { setFile(null); setUploadErr(null); setShowModal(false); };

  const handleFileChange = (e) => {
    const f = e.target.files?.[0];
    if (!f) return;
    setFile(f);
    setUploadErr(null);
  };

  const handleConfirmPaid = async () => {
    setActing(true);
    setUploadErr(null);
    let receiptUrl = null;

    if (file) {
      setUploading(true);
      const ext  = file.name.split(".").pop();
      const path = `${p.id}/${Date.now()}.${ext}`;
      const { error: upErr } = await sb.storage.from("payout-receipts").upload(path, file, { upsert: true });
      setUploading(false);
      if (upErr) {
        setUploadErr("Upload failed: " + upErr.message);
        setActing(false);
        return;
      }
      const { data: urlData } = await sb.storage.from("payout-receipts").createSignedUrl(path, 60 * 60 * 24 * 365);
      receiptUrl = urlData?.signedUrl ?? null;
    }

    const update = { status: "paid", paid_at: new Date().toISOString() };
    if (receiptUrl) update.payment_receipt_url = receiptUrl;

    const { error } = await sb.from("payouts").update(update).eq("id", p.id);
    if (error) {
      setUploadErr("Error saving payout: " + error.message);
      setActing(false);
      return;
    }
    onMarkPaid(p.id, receiptUrl);
    closeModal();
    setActing(false);
  };

  const statusChip = p.status === "paid" ? "pos" : p.status === "cancelled" ? "neg" : "warn";
  const typeLabel  = p.type === "sale" ? "Seller" : p.type === "delivery" ? "Driver" : p.type;

  // Seller payout breakdown from payout.breakdown JSONB
  const bd = p.breakdown || {};
  const bdSubtotal  = Number(bd.subtotal ?? gross);
  const bdTax       = Number(bd.tax_amount ?? 0);
  const bdSubsidy   = Number(bd.platform_subsidy_cost ?? 0);
  const bdCommAmt   = Number(bd.product_commission_amount ?? (gross - net));
  const bdCommRate  = bd.product_commission_rate != null
    ? `${(Number(bd.product_commission_rate) * 100).toFixed(1)}%`
    : rate;
  const bdSellerPre = Number(bd.seller_receives ?? gross);

  // Driver payout breakdown — treat as batch only when covering 2+ deliveries
  const isBatchPayout    = Array.isArray(bd.earnings) && bd.earnings.length > 1;
  const singleEarning    = !isBatchPayout && Array.isArray(bd.earnings) && bd.earnings[0];
  // For backfilled single-earnings rows, pull from earnings[0]; for distribute_order_payment rows use direct fields
  const bdDelivFee       = Number(bd.delivery_fee ?? singleEarning?.amount ?? gross);
  const bdDrvCommAmt     = Number(bd.delivery_commission_amount ?? (gross - net));
  const bdDrvCommRate    = bd.delivery_commission_rate != null
    ? `${(Number(bd.delivery_commission_rate) * 100).toFixed(1)}%`
    : rate;
  // For single backfilled rows, resolve order_number and tier from earnings[0]
  const singleOrderNumber = p.order_number ?? singleEarning?.order_number ?? null;
  const singleTier        = p.delivery_tier ?? singleEarning?.delivery_tier ?? null;

  return (
    <>
      <div className="panel-h">
        <span className="id" style={{ color: "var(--ink)" }}>
          {isBatchPayout
            ? `Batch · ${bd.earnings_count ?? bd.earnings.length} deliveries`
            : (singleOrderNumber || p.id.slice(0, 8).toUpperCase())}
        </span>
        <div className="right">
          <span className={"chip dot " + statusChip}>{p.status}</span>
          {singleTier && !isBatchPayout && (
            <span className={"chip dot " + (singleTier === "flash" ? "warn" : "info")} style={{ fontSize: 10 }}>
              {singleTier}
            </span>
          )}
          <span className="chip">{typeLabel}</span>
        </div>
      </div>

      {/* Hero amount */}
      <div style={{ padding: "14px", borderBottom: "1px solid var(--hairline)" }}>
        <div style={{ fontSize: 22, fontWeight: 550, letterSpacing: "-0.02em", color: "var(--ink)" }}>
          {D.currency(net)}
        </div>
        <div className="muted" style={{ fontSize: 11.5, marginTop: 2, fontFamily: "var(--font-mono)" }}>
          {p.created_at ? new Date(p.created_at).toLocaleString("en-US", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" }) : "—"}
          {p.paid_at ? ` · paid ${new Date(p.paid_at).toLocaleDateString("en-US", { month: "short", day: "numeric" })}` : ""}
        </div>
      </div>

      <div style={{ flex: 1, overflow: "auto" }}>

        {/* Payee */}
        <FinSection title="Payee">
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <div className="avatar" style={{ width: 30, height: 30, fontSize: 11 }}>
              {(name[0] || "?").toUpperCase()}
            </div>
            <div>
              <div style={{ fontWeight: 500, color: "var(--ink)" }}>{name}</div>
              {prof?.phone && <div className="muted" style={{ fontSize: 11, fontFamily: "var(--font-mono)" }}>{prof.phone}</div>}
            </div>
          </div>
        </FinSection>

        {/* Items from receipt snapshot */}
        {order && Array.isArray(order.items) && order.items.length > 0 && (
          <FinSection title="Items">
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              {order.items.map((item, idx) => {
                const itemName = item.product_name || item.name || "Product";
                const opts     = Array.isArray(item.selected_options) ? item.selected_options : [];
                return (
                  <div key={idx} style={{ display: "flex", alignItems: "flex-start", gap: 10, padding: "9px 10px", background: "var(--surface-2)", borderRadius: 6, border: "1px solid var(--hairline)" }}>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ display: "flex", alignItems: "baseline", gap: 6, flexWrap: "wrap" }}>
                        <span style={{ fontSize: 13, fontWeight: 600, color: "var(--ink)", lineHeight: 1.3 }}>{itemName}</span>
                        {item.quantity > 1 && (
                          <span style={{ fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>×{item.quantity}</span>
                        )}
                      </div>
                      {opts.length > 0 && (
                        <div style={{ display: "flex", flexWrap: "wrap", gap: 4, marginTop: 5 }}>
                          {opts.map((o, oi) => (
                            <span key={oi} style={{ fontSize: 10, fontWeight: 500, color: "var(--ink-2)", background: "var(--surface)", border: "1px solid var(--hairline)", borderRadius: 4, padding: "2px 7px", display: "inline-flex", alignItems: "center", gap: 3 }}>
                              <span style={{ color: "var(--ink-4)", fontWeight: 400 }}>{o.topic}:</span>
                              {o.value}
                              {o.price ? <span style={{ color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>+{D.currency(o.price)}</span> : null}
                            </span>
                          ))}
                        </div>
                      )}
                    </div>
                    <div style={{ textAlign: "right", flexShrink: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 700, color: "var(--ink)", fontFamily: "var(--font-mono)" }}>{D.currency(Number(item.total_price ?? item.unit_price ?? 0))}</div>
                      {item.quantity > 1 && (
                        <div style={{ fontSize: 10, color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>{D.currency(Number(item.unit_price ?? 0))} each</div>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>
          </FinSection>
        )}

        {/* Full order receipt — what the buyer paid (from receipt snapshot) */}
        <FinSection title="Order receipt">
          {loadOrd ? (
            <div className="muted" style={{ fontSize: 12 }}>Loading…</div>
          ) : order ? (() => {
            const pr = order.pricing || {};
            const dist = order.distribution || {};
            const couponTotal = Number(pr.coupon_discount_amount ?? pr.discount_amount ?? 0);
            const sellerCouponAmt = Number(dist.seller_coupon_amount ?? 0);
            const platformCouponAmt = couponTotal - sellerCouponAmt;
            const subsidyAmt = Number(pr.platform_subsidy_amount ?? 0);
            const manaAmt    = Number(pr.mana_discount_amount ?? 0);
            const manaPoints = pr.mana_points_used;
            const deliveryAmt = Number(pr.delivery_fee ?? 0);
            return (
              <div style={{ border: "1px solid var(--hairline)", borderRadius: 6, overflow: "hidden" }}>
                <div style={{ padding: "6px 10px", background: "var(--surface-2)", borderBottom: "1px solid var(--hairline)", fontSize: 9.5, fontFamily: "var(--font-mono)", color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.06em" }}>
                  What buyer paid · {dist.payment_method || "—"} · {pr.delivery_method || dist.sale_channel || "standard"}
                </div>
                <div style={{ padding: "10px 10px 8px" }}>
                  <FinRow k="Subtotal"          v={D.currency(Number(pr.subtotal ?? dist.subtotal ?? 0))}/>
                  <FinRow k={`Tax (${pr.tax_rate || "VAT"})`} v={D.currency(Number(pr.tax_amount ?? dist.tax_amount ?? 0))}/>
                  {deliveryAmt > 0 && <FinRow k="Delivery fee" v={D.currency(deliveryAmt)}/>}
                  {sellerCouponAmt > 0 && (
                    <FinRow k={`Coupon${pr.coupon_code ? ` (${pr.coupon_code})` : ""}`} v={`−${D.currency(sellerCouponAmt)}`} neg/>
                  )}
                  {platformCouponAmt > 0 && (
                    <FinRow k={`Coupon${pr.coupon_code ? ` (${pr.coupon_code})` : ""} · platform`} v={`−${D.currency(platformCouponAmt)}`} neg/>
                  )}
                  {subsidyAmt > 0 && (
                    <FinRow k="Platform subsidy" v={`−${D.currency(subsidyAmt)}`} neg/>
                  )}
                  {manaAmt > 0 && (
                    <FinRow k={`Mana${manaPoints ? ` (${manaPoints} pts)` : ""}`} v={`−${D.currency(manaAmt)}`} neg/>
                  )}
                  <div style={{ margin: "6px 0", borderTop: "1px solid var(--hairline)" }}/>
                  <FinRow k="Total charged"     v={D.currency(Number(pr.total_amount ?? dist.buyer_paid ?? 0))} bold/>
                </div>
              </div>
            );
          })() : (
            <div className="muted" style={{ fontSize: 12 }}>No receipt snapshot available</div>
          )}
        </FinSection>

        {/* Seller / Driver settlement breakdown */}
        <FinSection title="Settlement breakdown">
          <div style={{ border: "1px solid var(--hairline)", borderRadius: 6, overflow: "hidden" }}>
            <div style={{ padding: "6px 10px", background: "var(--surface-2)", borderBottom: "1px solid var(--hairline)", fontSize: 9.5, fontFamily: "var(--font-mono)", color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.06em" }}>
              {typeLabel} payout calculation
            </div>
            <div style={{ padding: "10px 10px 8px" }}>
              {p.type === "sale" ? (
                <>
                  <FinRow k="Subtotal"                      v={D.currency(bdSubtotal)}/>
                  <FinRow k="Tax (VAT)"                     v={D.currency(bdTax)}/>
                  {bdSubsidy > 0 && <FinRow k="Platform subsidy covered" v={`+${D.currency(bdSubsidy)}`}/>}
                  <FinRow k={`Commission (${bdCommRate || "—"})`}         v={`−${D.currency(bdCommAmt)}`} neg/>
                  <div style={{ margin: "6px 0", borderTop: "1px solid var(--hairline)" }}/>
                  <FinRow k="Seller receives (pre-fee)"     v={D.currency(bdSellerPre)} muted/>
                  <FinRow k="Net payout to seller"          v={D.currency(net)} bold/>
                </>
              ) : isBatchPayout ? (
                <>
                  {bd.earnings.map((e, i) => (
                    <div key={i} style={{ display: "flex", justifyContent: "space-between", padding: "3px 0" }}>
                      <span style={{ fontSize: 12, color: "var(--ink-3)" }}>
                        {e.order_number
                          ? <span className="id">{e.order_number}</span>
                          : <span style={{ color: "var(--ink-4)" }}>Delivery {i + 1}</span>}
                        {e.delivery_tier && (
                          <span className={"chip dot " + (e.delivery_tier === "flash" ? "warn" : "info")}
                            style={{ marginLeft: 5, fontSize: 9, padding: "1px 5px" }}>
                            {e.delivery_tier}
                          </span>
                        )}
                      </span>
                      <span className="num" style={{ fontSize: 12, color: "var(--ink)" }}>{D.currency(Number(e.amount))}</span>
                    </div>
                  ))}
                  <div style={{ margin: "6px 0", borderTop: "1px solid var(--hairline)" }}/>
                  <FinRow k={`Total (${bd.earnings_count ?? bd.earnings.length} deliveries)`} v={D.currency(net)} bold/>
                </>
              ) : (
                <>
                  <FinRow k="Delivery fee"                  v={D.currency(bdDelivFee)}/>
                  <FinRow k={`Commission (${bdDrvCommRate || "—"})`}      v={`−${D.currency(bdDrvCommAmt)}`} neg/>
                  <div style={{ margin: "6px 0", borderTop: "1px solid var(--hairline)" }}/>
                  <FinRow k="Net payout to driver"          v={D.currency(net)} bold/>
                </>
              )}
            </div>
          </div>
        </FinSection>

        {/* Reference */}
        <FinSection title="Reference">
          {isBatchPayout ? (
            <FinRow k="Deliveries" v={<span>{bd.earnings_count ?? bd.earnings.length} in batch</span>} muted/>
          ) : (
            <FinRow k="Order" v={
              p.resolved_order_id
                ? <window.EntityLink type="order" id={p.resolved_order_id} label={singleOrderNumber || p.resolved_order_id.slice(0, 8).toUpperCase()} style={{ fontSize: 12 }}/>
                : singleOrderNumber ? <span className="id">{singleOrderNumber}</span> : <span style={{ color: "var(--ink-4)" }}>—</span>
            } muted/>
          )}
          {!isBatchPayout && singleTier && (
            <FinRow k="Delivery type" v={
              <span className={"chip dot " + (singleTier === "flash" ? "warn" : "info")} style={{ fontSize: 10 }}>
                {singleTier}
              </span>
            } muted/>
          )}
          {p.delivery_id && <FinRow k="Delivery ID" v={<window.EntityLink type="delivery" id={p.delivery_id} label={p.delivery_id.slice(0, 8).toUpperCase()} style={{ fontSize: 12 }}/>} muted/>}
          <FinRow k="Payout ID" v={<span className="id">{p.id.slice(0, 8).toUpperCase()}</span>} muted/>
        </FinSection>

        {p.notes && (
          <FinSection title="Notes">
            <div style={{ fontSize: 12.5, color: "var(--ink-2)", lineHeight: 1.5 }}>{p.notes}</div>
          </FinSection>
        )}
      </div>

      {/* Actions */}
      <div style={{ padding: "10px 14px", borderTop: "1px solid var(--hairline)", display: "flex", gap: 6 }}>
        {p.status === "pending" && (
          <button className="btn primary grow" onClick={openModal} disabled={acting}>
            <I.check size={11}/>
            {acting ? "Saving…" : "Mark as paid"}
          </button>
        )}
        {p.status === "paid" && (
          <div style={{ display: "flex", alignItems: "center", gap: 8, flex: 1 }}>
            <div className="chip pos dot" style={{ height: 28, paddingLeft: 10, paddingRight: 10, fontSize: 12 }}>
              Paid {p.paid_at ? new Date(p.paid_at).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : ""}
            </div>
            {p.payment_receipt_url && (
              <a href={p.payment_receipt_url} target="_blank" rel="noreferrer"
                style={{ fontSize: 11, color: "var(--accent-ink)", fontFamily: "var(--font-mono)", marginLeft: "auto" }}>
                View receipt ↗
              </a>
            )}
          </div>
        )}
      </div>

      {/* Mark-as-paid modal */}
      {showModal && (
        <Modal
          title="Mark as paid"
          onClose={closeModal}
          footer={<>
            <button className="btn" onClick={closeModal} disabled={acting}>Cancel</button>
            <button className="btn primary" onClick={handleConfirmPaid} disabled={acting || uploading}>
              <I.check size={11}/>
              {uploading ? "Uploading…" : acting ? "Saving…" : "Confirm paid"}
            </button>
          </>}
        >
          <div style={{ background: "var(--surface-2)", borderRadius: 7, padding: "10px 12px", marginBottom: 16 }}>
            <div style={{ fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--font-mono)", marginBottom: 4 }}>
              {p.type === "sale" ? "Seller" : "Driver"} · {p.order_number || p.id.slice(0, 8).toUpperCase()}
            </div>
            <div style={{ fontSize: 20, fontWeight: 600, color: "var(--ink)", letterSpacing: "-0.02em" }}>{D.currency(net)}</div>
            <div style={{ fontSize: 12, color: "var(--ink-3)", marginTop: 2 }}>{name}</div>
          </div>
          <UploadArea file={file} preview={preview} onChange={handleFileChange} onRemove={() => setFile(null)}/>
          {uploadErr && <div style={{ fontSize: 12, color: "var(--neg)", marginTop: 8 }}>{uploadErr}</div>}
        </Modal>
      )}
    </>
  );
};

// ─────────────────────────────────────────────────────────────────────────────
// Transactions stub
// ─────────────────────────────────────────────────────────────────────────────

// Amounts under Rs 1 (ad spend debits are often a few paisa) round to "Rs 0"
// under D.currency's whole-rupee rounding — show 2 decimals for those instead.
const fmtWalletAmount = (D, n) => {
  const num = Number(n || 0);
  return Math.abs(num) > 0 && Math.abs(num) < 1 ? "Rs " + num.toFixed(2) : D.currency(num);
};

const AD_SPEND_REFERENCE_TYPE = "ad_spend_daily";
// reference_id on these types points at orders.id — safe to link to the order drawer.
const ORDER_LINKED_REFERENCE_TYPES = new Set(["order_payment", "order_refund"]);

// reference_type='p2p_payment' is overloaded in the DB — it covers real P2P
// transfers AND legacy direct-to-store wallet purchases from before the
// order_payment escrow flow existed (send_p2p_payment has had no live caller
// for purchases since; only interpersonal transfers still use it). Mirrors
// the parsing lib/transaction-label.ts already does for the mobile wallet UI,
// so the admin dashboard reads the same way instead of showing a raw
// "p2p_payment" chip on rows that are actually store purchases.
const REF_LABELS = {
  order_payment:   { chip: "info", label: "Order payment" },
  order_refund:    { chip: "warn", label: "Refund" },
  wallet_topup:    { chip: "pos",  label: "Top-up" },
  signup_reward:   { chip: "pos",  label: "Signup reward" },
  ad_spend_daily:  { chip: "neg",  label: "Ad spend" },
};

// Pulls the trailing order number token out of descriptions like
// "Order sale payout — Order NE1781121611788" / "Delivery for order NE…"
// so it can be rendered as its own clickable EntityLink inline.
const splitOrderDescription = (description) => {
  const m = (description || "").match(/^(.*\border\s+)(\S+)$/i);
  if (!m) return null;
  return { before: m[1], orderNumber: m[2] };
};

const classifyWalletTx = (r) => {
  if (r.reference_type !== "p2p_payment") {
    return {
      ...(REF_LABELS[r.reference_type] || { chip: "", label: r.reference_type || "—" }),
      description: r.description || "—",
    };
  }

  const body = (r.description || "").replace(/^p2p payment (sent|received):\s*/i, "");
  const purchaseAt = body.match(/^purchase at\s+(.+)/i);
  if (purchaseAt) {
    return { chip: "info", label: "Purchase (legacy)", description: body };
  }
  const paymentForOrder = body.match(/^payment for order\s+(\S+)/i);
  if (paymentForOrder) {
    return { chip: "info", label: "Order payment (legacy)", description: body };
  }
  return { chip: "", label: "P2P transfer", description: body || r.description || "—" };
};

const TransactionsSection = ({ D, I, sb }) => {
  const [rows,        setRows]        = useSt([]);
  const [loading,     setLoading]     = useSt(true);
  const [search,      setSearch]      = useSt("");
  const [hideAdSpend, setHideAdSpend] = useSt(true);

  useEf(() => {
    if (!sb) return;
    setLoading(true);
    sb.from("wallet_transactions")
      .select("id, wallet_id, amount, type, description, reference_type, reference_id, balance_after, created_at")
      .order("created_at", { ascending: false })
      .limit(200)
      .then(({ data, error }) => {
        setRows(error ? [] : (data || []));
        setLoading(false);
      });
  }, []);

  const adSpendCount = useMm(
    () => rows.filter(r => r.reference_type === AD_SPEND_REFERENCE_TYPE).length,
    [rows]
  );

  const filtered = useMm(() => {
    let list = hideAdSpend ? rows.filter(r => r.reference_type !== AD_SPEND_REFERENCE_TYPE) : rows;
    if (search.trim()) {
      const q = search.toLowerCase();
      list = list.filter(r =>
        (r.description || "").toLowerCase().includes(q) ||
        (r.type        || "").toLowerCase().includes(q) ||
        (r.reference_type || "").toLowerCase().includes(q)
      );
    }
    return list;
  }, [rows, search, hideAdSpend]);

  // wallet_transactions has no balance_before column — derive it from the
  // direction-aware amount and balance_after.
  const balanceBefore = (r) => {
    if (r.balance_after == null) return null;
    const amt = Number(r.amount || 0);
    return r.type === "credit" ? Number(r.balance_after) - amt : Number(r.balance_after) + amt;
  };

  const totals = useMm(() => ({
    credits: rows.filter(r => r.type === "credit").reduce((s, r) => s + Number(r.amount || 0), 0),
    debits:  rows.filter(r => r.type === "debit" ).reduce((s, r) => s + Number(r.amount || 0), 0),
  }), [rows]);

  return (
    <>
      <div className="kpi-grid" style={{ gridTemplateColumns: "repeat(3,1fr)", marginBottom: 18 }}>
        <div className="kpi">
          <div className="lbl">Wallet credits</div>
          <div className="val">{loading ? "—" : D.compactCurrency(totals.credits)}</div>
          <div className="sub"><span className="muted">{rows.filter(r=>r.type==="credit").length} txns</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Wallet debits</div>
          <div className="val">{loading ? "—" : D.compactCurrency(totals.debits)}</div>
          <div className="sub"><span className="muted">{rows.filter(r=>r.type==="debit").length} txns</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Net flow</div>
          <div className="val">{loading ? "—" : D.compactCurrency(totals.credits - totals.debits)}</div>
          <div className="sub"><span className="muted">{rows.length} total</span></div>
        </div>
      </div>

      <div className="panel">
        <div className="panel-h">
          <span>Wallet transactions</span>
          <div className="right" style={{ display: "flex", alignItems: "center", gap: 8 }}>
            {adSpendCount > 0 && (
              <button
                className={"btn" + (hideAdSpend ? " primary" : "")}
                style={{ height: 26, fontSize: 11.5, padding: "0 10px" }}
                onClick={() => setHideAdSpend(v => !v)}
              >
                {hideAdSpend ? `Ad spend hidden (${adSpendCount})` : "Hide ad spend"}
              </button>
            )}
            <div style={{ position: "relative" }}>
              <I.search size={12} style={{ position: "absolute", left: 10, top: "50%", transform: "translateY(-50%)", color: "var(--ink-4)", pointerEvents: "none" }}/>
              <input
                value={search} onChange={e => setSearch(e.target.value)}
                placeholder="Search description, type…"
                style={{ paddingLeft: 28, paddingRight: 10, height: 26, width: 220, background: "var(--surface-2)", border: "1px solid var(--hairline)", borderRadius: 5, fontSize: 12, color: "var(--ink)", outline: "none", fontFamily: "var(--font-sans)" }}
              />
            </div>
          </div>
        </div>
        <div className="t-wrap" style={{ overflow: "auto", maxHeight: 500 }}>
          {loading ? (
            <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>Loading transactions…</div>
          ) : (
            <table className="t">
              <thead>
                <tr>
                  <th>Type</th>
                  <th>Description</th>
                  <th>Reference</th>
                  <th style={{ textAlign: "right" }}>Amount</th>
                  <th style={{ textAlign: "right" }}>Balance before</th>
                  <th style={{ textAlign: "right" }}>Balance after</th>
                  <th>Date</th>
                </tr>
              </thead>
              <tbody>
                {filtered.map(r => {
                  const before = balanceBefore(r);
                  const isOrderLinked = ORDER_LINKED_REFERENCE_TYPES.has(r.reference_type) && r.reference_id;
                  const cls = classifyWalletTx(r);
                  const orderSplit = isOrderLinked ? splitOrderDescription(cls.description) : null;
                  return (
                    <tr
                      key={r.id}
                      style={isOrderLinked ? { cursor: "pointer" } : undefined}
                      onClick={isOrderLinked ? () => window.openEntity("order", r.reference_id) : undefined}
                    >
                      <td>
                        <span className={"chip dot " + (r.type === "credit" ? "pos" : "neg")}>
                          {r.type}
                        </span>
                      </td>
                      <td style={{ color: "var(--ink)", maxWidth: 280, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                        {orderSplit ? (
                          <>
                            {orderSplit.before}
                            <window.EntityLink type="order" id={r.reference_id} label={orderSplit.orderNumber} onClick={(e) => e.stopPropagation()}/>
                          </>
                        ) : cls.description}
                      </td>
                      <td className="muted" style={{ fontSize: 11 }} onClick={(e) => isOrderLinked && e.stopPropagation()}>
                        {isOrderLinked ? (
                          <window.EntityLink type="order" id={r.reference_id} label={cls.label} style={{ fontSize: 11 }}/>
                        ) : (
                          <span className={"chip dot " + (cls.chip || "")} style={{ fontFamily: "var(--font-sans)" }}>{cls.label}</span>
                        )}
                      </td>
                      <td className="num" style={{ textAlign: "right", color: r.type === "credit" ? "var(--pos)" : "var(--neg)", fontWeight: 550 }}>
                        {r.type === "credit" ? "+" : "−"}{fmtWalletAmount(D, Math.abs(Number(r.amount || 0)))}
                      </td>
                      <td className="num" style={{ textAlign: "right", color: "var(--ink-3)", fontSize: 11 }}>
                        {before != null ? fmtWalletAmount(D, before) : "—"}
                      </td>
                      <td className="num" style={{ textAlign: "right", color: "var(--ink-3)", fontSize: 11 }}>
                        {r.balance_after != null ? fmtWalletAmount(D, Number(r.balance_after)) : "—"}
                      </td>
                      <td className="muted" style={{ whiteSpace: "nowrap", fontSize: 11, fontFamily: "var(--font-mono)" }}>
                        {r.created_at ? new Date(r.created_at).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "—"}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </>
  );
};

// ─────────────────────────────────────────────────────────────────────────────
// Refunds stub
// ─────────────────────────────────────────────────────────────────────────────

const RefundsSection = ({ D, I, sb }) => {
  const [rows,    setRows]    = useSt([]);
  const [loading, setLoading] = useSt(true);

  useEf(() => {
    if (!sb) return;
    setLoading(true);
    sb.from("order_returns")
      .select("id, order_id, buyer_id, seller_id, status, reason, refund_amount, refund_method, refunded_at, created_at")
      .order("created_at", { ascending: false })
      .limit(200)
      .then(({ data, error }) => {
        setRows(error ? [] : (data || []));
        setLoading(false);
      });
  }, []);

  const kpis = useMm(() => ({
    refunded:  rows.filter(r => r.status === "refunded"),
    pending:   rows.filter(r => !["refunded","rejected","cancelled"].includes(r.status)),
    totalAmt:  rows.filter(r => r.status === "refunded").reduce((s, r) => s + Number(r.refund_amount || 0), 0),
  }), [rows]);

  const STATUS_CHIP = {
    requested: "warn", approved: "info", qr_generated: "info",
    dropped_off: "info", received: "warn", refunded: "pos",
    rejected: "neg", cancelled: "neg",
  };

  return (
    <>
      <div className="kpi-grid" style={{ gridTemplateColumns: "repeat(3,1fr)", marginBottom: 18 }}>
        <div className="kpi">
          <div className="lbl">Total refunded</div>
          <div className="val">{loading ? "—" : D.compactCurrency(kpis.totalAmt)}</div>
          <div className="sub"><span className="muted">{kpis.refunded.length} returns</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">In progress</div>
          <div className="val">{loading ? "—" : kpis.pending.length}</div>
          <div className="sub"><span className="chip warn dot">not yet refunded</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Total returns</div>
          <div className="val">{loading ? "—" : rows.length}</div>
          <div className="sub"><span className="muted">all time</span></div>
        </div>
      </div>

      <div className="panel">
        <div className="panel-h"><span>Return refunds</span></div>
        <div className="t-wrap" style={{ overflow: "auto", maxHeight: 500 }}>
          {loading ? (
            <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>Loading refunds…</div>
          ) : rows.length === 0 ? (
            <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>No returns yet</div>
          ) : (
            <table className="t">
              <thead>
                <tr>
                  <th>Return ID</th>
                  <th>Status</th>
                  <th>Reason</th>
                  <th>Method</th>
                  <th style={{ textAlign: "right" }}>Amount</th>
                  <th>Refunded at</th>
                  <th>Created</th>
                </tr>
              </thead>
              <tbody>
                {rows.map(r => (
                  <tr
                    key={r.id}
                    style={r.order_id ? { cursor: "pointer" } : undefined}
                    onClick={r.order_id ? () => window.openEntity("order", r.order_id) : undefined}
                  >
                    <td className="id">{r.id.slice(0, 8).toUpperCase()}</td>
                    <td><span className={"chip dot " + (STATUS_CHIP[r.status] || "warn")}>{r.status.replace(/_/g, " ")}</span></td>
                    <td className="muted" style={{ fontSize: 12 }}>{(r.reason || "—").replace(/_/g, " ")}</td>
                    <td className="muted" style={{ fontSize: 12, fontFamily: "var(--font-mono)" }}>{r.refund_method || "—"}</td>
                    <td className="num" style={{ textAlign: "right", color: r.refund_amount ? "var(--pos)" : "var(--ink-3)", fontWeight: r.refund_amount ? 550 : 400 }}>
                      {r.refund_amount ? D.currency(Number(r.refund_amount)) : "—"}
                    </td>
                    <td className="muted" style={{ whiteSpace: "nowrap", fontSize: 11, fontFamily: "var(--font-mono)" }}>
                      {r.refunded_at ? new Date(r.refunded_at).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "—"}
                    </td>
                    <td className="muted" style={{ whiteSpace: "nowrap", fontSize: 11, fontFamily: "var(--font-mono)" }}>
                      {r.created_at ? new Date(r.created_at).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "—"}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </>
  );
};

// ─────────────────────────────────────────────────────────────────────────────
// Alerts — finance_reconciliation_flags, written nightly by
// run_finance_reconciliation() (see supabase/migrations/20260819_finance_reconciliation.sql)
// ─────────────────────────────────────────────────────────────────────────────

const CHECK_META = {
  duplicate_sale_payout: {
    label: "Duplicate seller payout",
    describe: (d) => `${d.payout_count} payout rows, ${D_currency(d.total_amount)} total`,
  },
  duplicate_order_payment_wallet_tx: {
    label: "Duplicate wallet transaction",
    describe: (d) => `${d.tx_count} ${d.direction} rows, ${D_currency(d.total_amount)} total`,
  },
  order_delivered_multiple_times: {
    label: "Order re-delivered",
    describe: (d) => `Marked delivered ${d.delivered_count} times`,
  },
  seller_credit_mismatch: {
    label: "Seller credit mismatch",
    describe: (d) => `Expected ${D_currency(d.expected)}, actually credited ${D_currency(d.actually_credited)}`,
  },
};

// Small helper so CHECK_META can format currency without needing D threaded through.
function D_currency(n) {
  return "Rs " + Math.round(Number(n || 0)).toLocaleString("en-IN");
}

const AlertsSection = ({ D, I, sb, onChange }) => {
  const [rows,        setRows]        = useSt([]);
  const [loading,     setLoading]     = useSt(true);
  const [showResolved, setShowResolved] = useSt(false);
  const [running,     setRunning]     = useSt(false);

  const fetchFlags = () => {
    if (!sb) return;
    setLoading(true);
    sb.from("finance_reconciliation_flags")
      .select("id, check_name, severity, order_id, user_id, details, detected_at, resolved_at, resolution_notes")
      .order("detected_at", { ascending: false })
      .limit(200)
      .then(({ data, error }) => {
        setRows(error ? [] : (data || []));
        setLoading(false);
      });
  };

  useEf(() => { fetchFlags(); }, []);

  const filtered = useMm(
    () => showResolved ? rows : rows.filter(r => !r.resolved_at),
    [rows, showResolved]
  );

  const stats = useMm(() => ({
    openCritical: rows.filter(r => !r.resolved_at && r.severity === "critical").length,
    openWarning:  rows.filter(r => !r.resolved_at && r.severity === "warning").length,
    resolved:     rows.filter(r => r.resolved_at).length,
  }), [rows]);

  const runNow = () => {
    setRunning(true);
    sb.rpc("run_finance_reconciliation").then(() => {
      setRunning(false);
      fetchFlags();
      onChange?.();
    });
  };

  const resolveFlag = async (row) => {
    const notes = window.prompt(
      `Resolve "${CHECK_META[row.check_name]?.label || row.check_name}"?\nAdd a note (what was done):`,
      "",
    );
    if (notes === null) return; // cancelled
    const { data: { user } } = await sb.auth.getUser();
    await sb.from("finance_reconciliation_flags")
      .update({ resolved_at: new Date().toISOString(), resolved_by: user?.id || null, resolution_notes: notes })
      .eq("id", row.id);
    fetchFlags();
    onChange?.();
  };

  return (
    <>
      <div className="kpi-grid" style={{ gridTemplateColumns: "repeat(3,1fr)", marginBottom: 18 }}>
        <div className="kpi">
          <div className="lbl">Open · Critical</div>
          <div className="val">{loading ? "—" : stats.openCritical}</div>
          <div className="sub"><span className="chip neg dot">needs review</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Open · Warning</div>
          <div className="val">{loading ? "—" : stats.openWarning}</div>
          <div className="sub"><span className="chip warn dot">informational</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Resolved</div>
          <div className="val">{loading ? "—" : stats.resolved}</div>
          <div className="sub"><span className="muted">all time</span></div>
        </div>
      </div>

      <div className="panel">
        <div className="panel-h">
          <span>Reconciliation alerts</span>
          <div className="right" style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <button className={"btn" + (showResolved ? " primary" : "")} style={{ height: 26, fontSize: 11.5, padding: "0 10px" }}
              onClick={() => setShowResolved(v => !v)}>
              {showResolved ? "Showing all" : "Open only"}
            </button>
            <button className="btn" style={{ height: 26, fontSize: 11.5, padding: "0 10px" }} onClick={runNow} disabled={running}>
              {running ? "Running…" : "Run reconciliation now"}
            </button>
          </div>
        </div>
        <div className="t-wrap" style={{ overflow: "auto", maxHeight: 560 }}>
          {loading ? (
            <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>Loading alerts…</div>
          ) : filtered.length === 0 ? (
            <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>
              {showResolved ? "No alerts yet" : "No open alerts — clean"}
            </div>
          ) : (
            <table className="t">
              <thead>
                <tr>
                  <th>Severity</th>
                  <th>Check</th>
                  <th>Order</th>
                  <th>Details</th>
                  <th>Detected</th>
                  <th>Status</th>
                  <th></th>
                </tr>
              </thead>
              <tbody>
                {filtered.map(r => {
                  const meta = CHECK_META[r.check_name] || { label: r.check_name, describe: () => "—" };
                  return (
                    <tr key={r.id}>
                      <td><span className={"chip dot " + (r.severity === "critical" ? "neg" : "warn")}>{r.severity}</span></td>
                      <td style={{ color: "var(--ink)", fontSize: 12.5 }}>{meta.label}</td>
                      <td className="muted" style={{ fontSize: 11 }}>
                        {r.order_id
                          ? <window.EntityLink type="order" id={r.order_id} label={r.order_id.slice(0, 8).toUpperCase()} style={{ fontSize: 11 }}/>
                          : "—"}
                      </td>
                      <td className="muted" style={{ fontSize: 12, maxWidth: 320 }}>
                        {r.resolved_at ? r.resolution_notes || "Resolved" : meta.describe(r.details || {})}
                      </td>
                      <td className="muted" style={{ whiteSpace: "nowrap", fontSize: 11, fontFamily: "var(--font-mono)" }}>
                        {new Date(r.detected_at).toLocaleDateString("en-US", { month: "short", day: "numeric" })}
                      </td>
                      <td>
                        <span className={"chip dot " + (r.resolved_at ? "pos" : "neg")}>{r.resolved_at ? "resolved" : "open"}</span>
                      </td>
                      <td>
                        {!r.resolved_at && (
                          <button className="btn" style={{ height: 24, fontSize: 11, padding: "0 8px" }} onClick={() => resolveFlag(r)}>
                            Resolve
                          </button>
                        )}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </>
  );
};

// ─────────────────────────────────────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────────────────────────────────────

const FinSection = ({ title, children }) => (
  <div style={{ padding: "14px", borderBottom: "1px solid var(--hairline)" }}>
    <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-3)", letterSpacing: "0.06em", textTransform: "uppercase", marginBottom: 8 }}>{title}</div>
    {children}
  </div>
);

const FinRow = ({ k, v, bold, muted, neg }) => (
  <div style={{ display: "flex", justifyContent: "space-between", padding: "3px 0" }}>
    <span style={{ fontSize: 12.5, color: muted ? "var(--ink-3)" : neg ? "var(--neg)" : "var(--ink-2)" }}>{k}</span>
    <span className="num" style={{ fontSize: 12.5, fontWeight: bold ? 600 : 500, color: muted ? "var(--ink-3)" : neg ? "var(--neg)" : "var(--ink)", whiteSpace: "nowrap" }}>{v}</span>
  </div>
);

window.FinancePage = FinancePage;
