const { useState: useStateA, useMemo: useMemoA, useEffect: useEffectA } = React;

const AnalyticsPage = () => {
  const D = window.PipalData;
  const I = window.Icons;
  const sb = window.supabaseClient;
  const [view, setView] = useStateA("overview");
  const [range, setRange] = useStateA("30D");
  const [loading, setLoading] = useStateA(true);

  // ── raw data ───────────────────────────────────────────────────────────────
  const [allOrders, setAllOrders] = useStateA([]);
  const [storeMap, setStoreMap] = useStateA({});
  const [drivers, setDrivers] = useStateA([]);
  const [topBuyersRaw, setTopBuyersRaw] = useStateA([]);

  const doFetch = async () => {
    if (!sb) return;
    setLoading(true);
    const [ordersRes, driversRes] = await Promise.all([
      sb.from('orders')
        .select('id, buyer_id, store_id, total_amount, platform_fee_amount, order_status, created_at')
        .order('created_at', { ascending: true }),
      sb.from('delivery_partners')
        .select('user_id, vehicle_type, coverage_city, total_deliveries, completed_deliveries, rating, total_earnings, current_month_earnings, is_online, is_active'),
    ]);
    const orders = ordersRes.data || [];
    setAllOrders(orders);

    // fetch store info for category breakdown
    const storeIds = [...new Set(orders.map(o => o.store_id).filter(Boolean))];
    if (storeIds.length) {
      const { data: stores } = await sb.from('stores').select('id, name, category').in('id', storeIds);
      const sm = {};
      (stores || []).forEach(s => { sm[s.id] = s; });
      setStoreMap(sm);
    }

    // fetch top buyers with display names
    const buyerIds = [...new Set(orders.map(o => o.buyer_id).filter(Boolean))];
    if (buyerIds.length) {
      const { data: profiles } = await sb.from('user_profiles').select('id, display_name').in('id', buyerIds);
      const profileMap = {};
      (profiles || []).forEach(p => { profileMap[p.id] = p.display_name || 'Unknown'; });
      const buyerAgg = {};
      orders.forEach(o => {
        if (!o.buyer_id) return;
        if (!buyerAgg[o.buyer_id]) buyerAgg[o.buyer_id] = { name: profileMap[o.buyer_id] || '—', total: 0, count: 0, first: o.created_at };
        buyerAgg[o.buyer_id].total += Number(o.total_amount || 0);
        buyerAgg[o.buyer_id].count++;
      });
      setTopBuyersRaw(Object.values(buyerAgg).sort((a, b) => b.total - a.total).slice(0, 8));
    }

    // enrich drivers with names
    const driversList = driversRes.data || [];
    const driverIds = driversList.map(d => d.user_id).filter(Boolean);
    if (driverIds.length) {
      const { data: profiles } = await sb.from('user_profiles').select('id, display_name').in('id', driverIds);
      const pm = {};
      (profiles || []).forEach(p => { pm[p.id] = p.display_name || '—'; });
      setDrivers(driversList.map(d => ({ ...d, display_name: pm[d.user_id] || '—' }))
        .filter(d => d.is_active)
        .sort((a, b) => (b.completed_deliveries || 0) - (a.completed_deliveries || 0)));
    } else {
      setDrivers(driversList);
    }

    setLoading(false);
  };

  useEffectA(() => { doFetch(); }, []);

  // ── range filtering ────────────────────────────────────────────────────────
  const rangeDays = { '7D': 7, '30D': 30, '90D': 90, '1Y': 365, 'ALL': Infinity };

  const filteredOrders = useMemoA(() => {
    const days = rangeDays[range];
    if (!isFinite(days)) return allOrders;
    const cutoff = Date.now() - days * 86400000;
    return allOrders.filter(o => new Date(o.created_at) >= cutoff);
  }, [allOrders, range]);

  const prevOrders = useMemoA(() => {
    const days = rangeDays[range];
    if (!isFinite(days)) return [];
    const end = Date.now() - days * 86400000;
    const start = end - days * 86400000;
    return allOrders.filter(o => { const t = new Date(o.created_at).getTime(); return t >= start && t < end; });
  }, [allOrders, range]);

  // ── KPIs ──────────────────────────────────────────────────────────────────
  const gmv = useMemoA(() => filteredOrders.reduce((s, o) => s + Number(o.total_amount || 0), 0), [filteredOrders]);
  const gmvPrev = useMemoA(() => prevOrders.reduce((s, o) => s + Number(o.total_amount || 0), 0), [prevOrders]);
  const gmvDelta = gmvPrev > 0 ? ((gmv - gmvPrev) / gmvPrev * 100) : null;

  const platformFees = useMemoA(() => filteredOrders.reduce((s, o) => s + Number(o.platform_fee_amount || 0), 0), [filteredOrders]);
  const takeRate = gmv > 0 ? (platformFees / gmv * 100) : null;

  const delivered = filteredOrders.filter(o => o.order_status === 'delivered').length;
  const cancelled = filteredOrders.filter(o => o.order_status === 'cancelled').length;
  const fulfillmentRate = (delivered + cancelled) > 0 ? (delivered / (delivered + cancelled) * 100) : null;

  const aov = filteredOrders.length > 0 ? gmv / filteredOrders.length : 0;
  const aovPrev = prevOrders.length > 0 ? gmvPrev / prevOrders.length : 0;
  const aovDelta = aovPrev > 0 ? ((aov - aovPrev) / aovPrev * 100) : null;

  // ── chart series ──────────────────────────────────────────────────────────
  const { currentSeries, prevSeries, chartLabels } = useMemoA(() => {
    const days = Math.min(rangeDays[range], 90);
    const buckets = isFinite(days) ? days : 90;
    const cur = Array(buckets).fill(0);
    const prev = Array(buckets).fill(0);
    const now = Date.now();

    filteredOrders.forEach(o => {
      const idx = buckets - 1 - Math.floor((now - new Date(o.created_at).getTime()) / 86400000);
      if (idx >= 0 && idx < buckets) cur[idx] += Number(o.total_amount || 0);
    });
    prevOrders.forEach(o => {
      const cutoff = now - (isFinite(days) ? days : 90) * 86400000;
      const idx = buckets - 1 - Math.floor((cutoff - new Date(o.created_at).getTime()) / 86400000);
      if (idx >= 0 && idx < buckets) prev[idx] += Number(o.total_amount || 0);
    });

    // Labels: show every ~14th for long ranges, every 7th for short
    const step = buckets <= 14 ? 2 : buckets <= 30 ? 7 : 14;
    const labels = Array.from({ length: buckets }, (_, i) => {
      if (i % step !== 0 && i !== buckets - 1) return '';
      const dt = new Date(now - (buckets - 1 - i) * 86400000);
      return dt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
    });
    return { currentSeries: cur, prevSeries: prev, chartLabels: labels };
  }, [filteredOrders, prevOrders, range]);

  // ── categories ────────────────────────────────────────────────────────────
  const categories = useMemoA(() => {
    const agg = {};
    filteredOrders.forEach(o => {
      const cat = (storeMap[o.store_id]?.category || 'Other');
      if (!agg[cat]) agg[cat] = { gmv: 0, count: 0 };
      agg[cat].gmv += Number(o.total_amount || 0);
      agg[cat].count++;
    });
    const rows = Object.entries(agg).map(([n, v]) => ({ n, gmv: v.gmv, count: v.count }))
      .sort((a, b) => b.gmv - a.gmv);
    const total = rows.reduce((s, r) => s + r.gmv, 0) || 1;
    return rows.map(r => ({ ...r, share: (r.gmv / total * 100) }));
  }, [filteredOrders, storeMap]);

  // ── order funnel (from status data) ──────────────────────────────────────
  const funnel = useMemoA(() => {
    const total = filteredOrders.length;
    const processing = filteredOrders.filter(o => ['processing','shipped','delivered','cancelled'].includes(o.order_status)).length;
    const shipped = filteredOrders.filter(o => ['shipped','delivered','cancelled'].includes(o.order_status)).length;
    const del = filteredOrders.filter(o => o.order_status === 'delivered').length;
    return [
      { label: 'Orders placed',    v: total },
      { label: 'Processing',       v: processing },
      { label: 'Shipped / routed', v: Math.max(shipped, del) },
      { label: 'Delivered',        v: del },
    ].filter(s => s.v > 0);
  }, [filteredOrders]);

  // ── cohort retention ──────────────────────────────────────────────────────
  const cohorts = useMemoA(() => {
    // Build: first order month per buyer
    const firstMonth = {};
    allOrders.forEach(o => {
      if (!o.buyer_id) return;
      const m = new Date(o.created_at).toISOString().slice(0, 7);
      if (!firstMonth[o.buyer_id] || m < firstMonth[o.buyer_id]) firstMonth[o.buyer_id] = m;
    });
    // For each cohort month, track how many buyers ordered in month+N
    const cohortMap = {};
    allOrders.forEach(o => {
      if (!o.buyer_id) return;
      const cm = firstMonth[o.buyer_id];
      const om = new Date(o.created_at).toISOString().slice(0, 7);
      const [cy, cmo] = cm.split('-').map(Number);
      const [oy, omo] = om.split('-').map(Number);
      const offset = (oy - cy) * 12 + (omo - cmo);
      if (!cohortMap[cm]) cohortMap[cm] = {};
      cohortMap[cm][offset] = (cohortMap[cm][offset] || new Set()).add(o.buyer_id);
    });
    // cohort sizes
    const cohortSizes = {};
    Object.keys(firstMonth).forEach(bid => {
      const cm = firstMonth[bid];
      cohortSizes[cm] = (cohortSizes[cm] || 0) + 1;
    });
    return Object.keys(cohortMap).sort().map(cm => {
      const size = cohortSizes[cm] || 1;
      const maxOffset = Math.max(...Object.keys(cohortMap[cm]).map(Number));
      const row = Array.from({ length: maxOffset + 1 }, (_, i) =>
        cohortMap[cm][i] ? cohortMap[cm][i].size / size : null
      );
      return {
        month: new Date(cm + '-01').toLocaleDateString('en-US', { month: 'short', year: '2-digit' }),
        sized: size,
        row,
      };
    });
  }, [allOrders]);

  // ── range date labels ──────────────────────────────────────────────────────
  const rangeLabel = useMemoA(() => {
    const days = rangeDays[range];
    if (!isFinite(days)) {
      if (!allOrders.length) return '';
      const first = new Date(allOrders[0].created_at);
      return `${first.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: '2-digit' })} → today`;
    }
    const start = new Date(Date.now() - days * 86400000);
    return `${start.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} → today`;
  }, [range, allOrders]);

  return (
    <div className="page" data-screen-label="07 Analytics">
      <div className="page-h">
        <div>
          <div className="ts">All times NPT · datasource: Supabase</div>
          <h1>Analytics</h1>
        </div>
        <div className="acts">
          <div className="row gap-2">
            {["7D","30D","90D","1Y","ALL"].map(r =>
              <span key={r} onClick={() => setRange(r)} className="chip" style={{
                cursor: "pointer",
                background: r === range ? "var(--accent-soft)" : undefined,
                color: r === range ? "var(--accent-ink)" : undefined,
                borderColor: r === range ? "transparent" : undefined,
              }}>{r}</span>
            )}
          </div>
          <button className="btn" onClick={doFetch}><I.refresh size={12}/>Refresh</button>
        </div>
      </div>

      {/* Sub-views */}
      <div className="ftabs" style={{marginBottom:16}}>
        {[
          ["overview","Overview"],
          ["retention","Retention"],
          ["catalog","Catalog"],
        ].map(([id,name]) => (
          <div key={id} className={"ftab"+(view===id?" active":"")} onClick={()=>setView(id)}>{name}</div>
        ))}
      </div>

      {/* KPI strip — overview only */}
      {view === 'overview' && <div className="kpi-grid">
        <div className="kpi">
          <div className="lbl">GMV · {range}</div>
          <div className="val">{loading ? '—' : D.compactCurrency(gmv)}</div>
          <div className="sub">
            {!loading && gmvDelta !== null
              ? <><span className={`delta ${gmvDelta >= 0 ? 'up' : 'dn'}`}>{gmvDelta >= 0 ? <I.arrowUp size={10}/> : <I.arrowDn size={10}/>}{Math.abs(gmvDelta).toFixed(1)}%</span><span>vs prev period</span></>
              : <span className="muted">{loading ? '' : `${filteredOrders.length} orders`}</span>}
          </div>
        </div>
        <div className="kpi">
          <div className="lbl">Orders · {range}</div>
          <div className="val">{loading ? '—' : filteredOrders.length.toLocaleString()}</div>
          <div className="sub">
            {!loading && prevOrders.length > 0
              ? <><span className={`delta ${filteredOrders.length >= prevOrders.length ? 'up' : 'dn'}`}>
                  {filteredOrders.length >= prevOrders.length ? <I.arrowUp size={10}/> : <I.arrowDn size={10}/>}
                  {Math.abs(((filteredOrders.length - prevOrders.length) / prevOrders.length) * 100).toFixed(1)}%
                </span><span>vs prev period</span></>
              : <span className="muted">{loading ? '' : `${delivered} delivered · ${cancelled} cancelled`}</span>}
          </div>
        </div>
        <div className="kpi">
          <div className="lbl">Avg order value</div>
          <div className="val">{loading ? '—' : aov > 0 ? D.compactCurrency(aov) : '—'}</div>
          <div className="sub">
            {!loading && aovDelta !== null
              ? <><span className={`delta ${aovDelta >= 0 ? 'up' : 'dn'}`}>{aovDelta >= 0 ? <I.arrowUp size={10}/> : <I.arrowDn size={10}/>}{Math.abs(aovDelta).toFixed(1)}%</span><span>vs prev period</span></>
              : <span className="muted">{loading ? '' : rangeLabel}</span>}
          </div>
        </div>
        <div className="kpi">
          <div className="lbl">Take rate</div>
          <div className="val">{loading ? '—' : takeRate !== null ? takeRate.toFixed(1) : '—'}<span className="unit">{!loading && takeRate !== null ? '%' : ''}</span></div>
          <div className="sub"><span className="muted">{loading ? '' : 'platform fees / GMV'}</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Fulfillment rate</div>
          <div className="val">{loading ? '—' : fulfillmentRate !== null ? fulfillmentRate.toFixed(1) : '—'}<span className="unit">{!loading && fulfillmentRate !== null ? '%' : ''}</span></div>
          <div className="sub">
            {!loading && fulfillmentRate !== null
              ? <span className={`chip dot ${fulfillmentRate >= 80 ? 'pos' : fulfillmentRate >= 60 ? 'warn' : 'neg'}`}>{fulfillmentRate >= 80 ? 'healthy' : fulfillmentRate >= 60 ? 'moderate' : 'low'}</span>
              : <span className="muted">{loading ? '' : 'no completed orders'}</span>}
          </div>
        </div>
      </div>}

      {/* GMV chart + funnel — overview only */}
      {view === 'overview' &&
      <div className="mob-stack" style={{display:"grid", gridTemplateColumns:"1.6fr 1fr", gap:14, marginTop:14}}>
        <div className="panel">
          <div className="panel-h">
            <span>GMV · {range}</span>
            <div className="right">
              <Legend color="var(--accent)" label="Current"/>
              {prevOrders.length > 0 && <Legend color="var(--ink-4)" label="Previous"/>}
            </div>
          </div>
          <div style={{padding:"14px"}}>
            <div className="row" style={{alignItems:"baseline", gap:18, marginBottom:6}}>
              <div style={{fontSize:24, fontWeight:550, letterSpacing:"-0.02em"}}>{loading ? '—' : D.compactCurrency(gmv)}</div>
              {!loading && gmvDelta !== null && (
                <div className={`delta ${gmvDelta >= 0 ? 'up' : 'dn'}`}>
                  {gmvDelta >= 0 ? <I.arrowUp size={10}/> : <I.arrowDn size={10}/>}{Math.abs(gmvDelta).toFixed(1)}%
                </div>
              )}
              <div className="muted" style={{marginLeft:"auto", fontFamily:"var(--font-mono)", fontSize:11}}>{rangeLabel}</div>
            </div>
            {loading
              ? <div className="muted" style={{height:220, display:'flex', alignItems:'center', justifyContent:'center', fontSize:12}}>Loading…</div>
              : <DualLineChart current={currentSeries} previous={prevOrders.length > 0 ? prevSeries : []} height={220} labels={chartLabels}/>}
          </div>
        </div>

        <div className="panel">
          <div className="panel-h">
            <span>Order lifecycle · {range}</span>
            <span className="meta">{loading ? '' : `${filteredOrders.length} total`}</span>
          </div>
          <div style={{padding:"16px 18px"}}>
            {loading
              ? <div className="muted" style={{fontSize:12}}>Loading…</div>
              : funnel.length === 0
                ? <div className="muted" style={{fontSize:12, textAlign:'center', padding:'32px 0'}}>No orders in this period</div>
                : <Funnel data={funnel}/>}
          </div>
        </div>
      </div>}

      {/* Categories — overview (gridded with drivers) or catalog (full-width) */}
      {(view === 'overview' || view === 'catalog') && (
      <div className="mob-stack" style={{display:"grid", gridTemplateColumns: view === 'overview' ? "1.4fr 1fr" : "1fr", gap:14, marginTop:14}}>
        <div className="panel">
          <div className="panel-h">
            <span>Categories · GMV share</span>
            <span className="meta">{range}</span>
          </div>
          <div style={{padding:"14px 16px"}}>
            {loading ? (
              <div className="muted" style={{fontSize:12}}>Loading…</div>
            ) : categories.length === 0 ? (
              <div className="muted" style={{fontSize:12, textAlign:'center', padding:'24px 0'}}>No data for this period</div>
            ) : (
              <>
                <div style={{display:"flex", height:14, borderRadius:3, overflow:"hidden", background:"var(--surface-2)"}}>
                  {categories.map((c, i) => (
                    <div key={c.n} style={{width: c.share + "%", background: catColor(i), borderRight: i < categories.length - 1 ? "1px solid var(--surface)" : "none"}}/>
                  ))}
                </div>
                <table className="t" style={{marginTop:14}}>
                  <thead><tr>
                    <th>Category</th>
                    <th style={{textAlign:"right"}}>Orders</th>
                    <th style={{textAlign:"right"}}>GMV</th>
                    <th style={{textAlign:"right"}}>Share</th>
                  </tr></thead>
                  <tbody>
                    {categories.map((c, i) => (
                      <tr key={c.n}>
                        <td>
                          <div className="row gap-2">
                            <span style={{width:8, height:8, borderRadius:2, background: catColor(i), flexShrink:0}}/>
                            <span style={{fontWeight:500, color:"var(--ink)", textTransform:"capitalize"}}>{c.n}</span>
                          </div>
                        </td>
                        <td className="num" style={{textAlign:"right"}}>{c.count}</td>
                        <td className="num" style={{textAlign:"right"}}>{D.compactCurrency(c.gmv)}</td>
                        <td className="num" style={{textAlign:"right"}}>{c.share.toFixed(1)}%</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </>
            )}
          </div>
        </div>

        {view === 'overview' && <div className="panel">
          <div className="panel-h">
            <span>Top drivers</span>
            <span className="meta">all-time</span>
          </div>
          {loading ? (
            <div className="muted" style={{padding:16, fontSize:12}}>Loading…</div>
          ) : drivers.length === 0 ? (
            <div className="muted" style={{padding:24, textAlign:'center', fontSize:12}}>No driver data</div>
          ) : (
            <div className="t-wrap"><table className="t">
              <thead><tr>
                <th>Driver</th>
                <th style={{textAlign:"right"}}>Trips</th>
                <th style={{textAlign:"right"}}>Done</th>
                <th style={{textAlign:"right"}}>Rating</th>
                <th style={{textAlign:"right"}}>Earnings</th>
              </tr></thead>
              <tbody>
                {drivers.slice(0, 6).map(d => {
                  const compRate = d.total_deliveries > 0 ? d.completed_deliveries / d.total_deliveries * 100 : null;
                  return (
                    <tr key={d.user_id}>
                      <td>
                        <div className="row gap-2">
                          <div className="avatar" style={{width:22, height:22, fontSize:9}}>
                            {(d.display_name || '?').split(' ').map(s => s[0]).join('').slice(0, 2).toUpperCase()}
                          </div>
                          <div>
                            <div style={{color:"var(--ink)", fontWeight:500}}>{d.display_name}</div>
                            <div className="id">{d.vehicle_type} · {d.coverage_city}</div>
                          </div>
                        </div>
                      </td>
                      <td className="num" style={{textAlign:"right"}}>{d.total_deliveries || 0}</td>
                      <td style={{textAlign:"right"}}>
                        {compRate !== null
                          ? <span className={`chip dot ${compRate >= 90 ? 'pos' : compRate >= 70 ? '' : 'warn'}`}>{compRate.toFixed(0)}%</span>
                          : <span className="muted">—</span>}
                      </td>
                      <td className="num" style={{textAlign:"right"}}>
                        {d.rating ? <span className="chip accent">{Number(d.rating).toFixed(1)} ★</span> : <span className="muted">—</span>}
                      </td>
                      <td className="num" style={{textAlign:"right"}}>{D.compactCurrency(d.total_earnings || 0)}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table></div>
          )}
        </div>}
      </div>
      )}

      {/* Catalog: full-width drivers */}
      {view === 'catalog' && (
        <div className="panel" style={{marginTop:14}}>
          <div className="panel-h">
            <span>Top drivers</span>
            <span className="meta">all-time</span>
          </div>
          {loading ? (
            <div className="muted" style={{padding:16, fontSize:12}}>Loading…</div>
          ) : drivers.length === 0 ? (
            <div className="muted" style={{padding:24, textAlign:'center', fontSize:12}}>No driver data</div>
          ) : (
            <div className="t-wrap"><table className="t">
              <thead><tr>
                <th>Driver</th>
                <th style={{textAlign:"right"}}>Trips</th>
                <th style={{textAlign:"right"}}>Done</th>
                <th style={{textAlign:"right"}}>Rating</th>
                <th style={{textAlign:"right"}}>Earnings</th>
              </tr></thead>
              <tbody>
                {drivers.map(d => {
                  const compRate = d.total_deliveries > 0 ? d.completed_deliveries / d.total_deliveries * 100 : null;
                  return (
                    <tr key={d.user_id}>
                      <td>
                        <div className="row gap-2">
                          <div className="avatar" style={{width:22, height:22, fontSize:9}}>
                            {(d.display_name || '?').split(' ').map(s => s[0]).join('').slice(0, 2).toUpperCase()}
                          </div>
                          <div>
                            <div style={{color:"var(--ink)", fontWeight:500}}>{d.display_name}</div>
                            <div className="id">{d.vehicle_type} · {d.coverage_city}</div>
                          </div>
                        </div>
                      </td>
                      <td className="num" style={{textAlign:"right"}}>{d.total_deliveries || 0}</td>
                      <td style={{textAlign:"right"}}>
                        {compRate !== null
                          ? <span className={`chip dot ${compRate >= 90 ? 'pos' : compRate >= 70 ? '' : 'warn'}`}>{compRate.toFixed(0)}%</span>
                          : <span className="muted">—</span>}
                      </td>
                      <td className="num" style={{textAlign:"right"}}>
                        {d.rating ? <span className="chip accent">{Number(d.rating).toFixed(1)} ★</span> : <span className="muted">—</span>}
                      </td>
                      <td className="num" style={{textAlign:"right"}}>{D.compactCurrency(d.total_earnings || 0)}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table></div>
          )}
        </div>
      )}

      {/* Cohort retention — retention only */}
      {view === 'retention' && (
        <div className="panel" style={{marginTop:14}}>
          <div className="panel-h">
            <span>Cohort retention · monthly</span>
            <span className="meta">% of cohort placing ≥1 order</span>
          </div>
          <div style={{padding:"16px 18px", overflow:"auto"}}>
            {loading
              ? <div className="muted" style={{fontSize:12}}>Loading…</div>
              : cohorts.length === 0
                ? <div className="muted" style={{fontSize:12, textAlign:'center', padding:'24px 0'}}>Not enough data for cohort analysis</div>
                : <CohortGrid cohorts={cohorts}/>}
          </div>
        </div>
      )}

      {/* Top buyers — retention + catalog */}
      {(view === 'retention' || view === 'catalog') && <div className="panel" style={{marginTop:14}}>
        <div className="panel-h">
          <span>Top buyers · lifetime value</span>
          <span className="meta">all-time</span>
        </div>
        {loading ? (
          <div className="muted" style={{padding:16, fontSize:12}}>Loading…</div>
        ) : topBuyersRaw.length === 0 ? (
          <div className="muted" style={{padding:24, textAlign:'center', fontSize:12}}>No buyer data</div>
        ) : (
          <div className="t-wrap"><table className="t">
            <thead><tr>
              <th>#</th><th>Buyer</th>
              <th style={{textAlign:"right"}}>Orders</th>
              <th style={{textAlign:"right"}}>LTV</th>
              <th style={{textAlign:"right"}}>AOV</th>
              <th>First order</th>
            </tr></thead>
            <tbody>
              {topBuyersRaw.map((b, i) => (
                <tr key={b.name + i}>
                  <td className="num muted">{String(i+1).padStart(2,'0')}</td>
                  <td>
                    <div className="row gap-2">
                      <div className="avatar" style={{width:22, height:22, fontSize:9}}>
                        {b.name.split(' ').map(s => s[0]).join('').slice(0,2).toUpperCase()}
                      </div>
                      <span style={{color:"var(--ink)", fontWeight:500}}>{b.name}</span>
                    </div>
                  </td>
                  <td className="num" style={{textAlign:"right"}}>{b.count}</td>
                  <td className="num" style={{textAlign:"right", color:"var(--ink)"}}>{D.compactCurrency(b.total)}</td>
                  <td className="num" style={{textAlign:"right"}}>{D.currency(b.total / b.count)}</td>
                  <td className="muted" style={{fontFamily:"var(--font-mono)", fontSize:11}}>
                    {new Date(b.first).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: '2-digit' })}
                  </td>
                </tr>
              ))}
            </tbody>
          </table></div>
        )}
      </div>}
    </div>
  );
};

function catColor(i) {
  const hues = [145, 235, 28, 75, 320, 200];
  return `oklch(60% 0.13 ${hues[i % hues.length]})`;
}

const Legend = ({color,label}) => (
  <div className="row gap-2" style={{fontSize:11, color:"var(--ink-3)", fontFamily:"var(--font-mono)"}}>
    <span style={{width:12, height:2, background:color, borderRadius:1}}/>{label}
  </div>
);

const DualLineChart = ({current, previous = [], height = 220, labels = []}) => {
  const { useRef, useEffect, useState, useId } = React;
  const ref = useRef(null);
  const [w, setW] = useState(600);
  useEffect(() => {
    if (!ref.current) return;
    const ro = new ResizeObserver(([e]) => setW(e.contentRect.width));
    ro.observe(ref.current); return () => ro.disconnect();
  }, []);
  const id = useId().replace(/:/g, "");
  const padL = 44, padR = 8, padT = 14, padB = 22;
  const innerW = w - padL - padR, innerH = height - padT - padB;
  const hasPrev = previous.length > 0 && previous.some(v => v > 0);
  const all = hasPrev ? [...current, ...previous] : current;
  const minV = Math.min(...all), maxV = Math.max(...all, 1);
  const dataRange = maxV - minV || 1;
  const mkPath = (data) => {
    if (data.length < 2) return '';
    return data.map((v, i) => {
      const x = padL + (i / (data.length - 1)) * innerW;
      const y = padT + innerH - ((v - minV) / dataRange) * innerH;
      return `${i === 0 ? 'M' : 'L'} ${x.toFixed(2)} ${y.toFixed(2)}`;
    }).join(' ');
  };
  const ticks = Array.from({length: 5}, (_, i) => minV + (dataRange * i) / 4);
  const curPath = mkPath(current);
  return (
    <div ref={ref} style={{width: "100%", height}}>
      <svg width={w} height={height} style={{display: "block"}}>
        <defs>
          <linearGradient id={"al" + id} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor="var(--accent)" stopOpacity="0.18"/>
            <stop offset="1" stopColor="var(--accent)" stopOpacity="0"/>
          </linearGradient>
        </defs>
        {ticks.map((t, i) => {
          const y = padT + innerH - ((t - minV) / dataRange) * innerH;
          return (
            <g key={i}>
              <line x1={padL} x2={w - padR} y1={y} y2={y} stroke="var(--hairline)"/>
              <text x={padL - 8} y={y + 3} textAnchor="end" fill="var(--ink-3)" fontFamily="var(--font-mono)" fontSize="9.5">
                {window.PipalData.compactCurrency(t)}
              </text>
            </g>
          );
        })}
        {/* x-axis labels */}
        {labels.map((l, i) => {
          if (!l) return null;
          const x = padL + (i / (current.length - 1)) * innerW;
          return <text key={i} x={x} y={height - 5} textAnchor="middle" fill="var(--ink-3)" fontFamily="var(--font-mono)" fontSize="9.5">{l}</text>;
        })}
        {hasPrev && <path d={mkPath(previous)} fill="none" stroke="var(--ink-4)" strokeWidth="1.25" strokeDasharray="3 3"/>}
        {curPath && <path d={curPath + ` L ${padL + innerW} ${padT + innerH} L ${padL} ${padT + innerH} Z`} fill={"url(#al" + id + ")"}/>}
        {curPath && <path d={curPath} fill="none" stroke="var(--accent)" strokeWidth="1.5"/>}
      </svg>
    </div>
  );
};

const Funnel = ({data}) => {
  const max = data[0].v;
  return (
    <div style={{display:"flex", flexDirection:"column", gap:10}}>
      {data.map((d, i) => {
        const w = (d.v/max)*100;
        const conv = i>0 ? (d.v/data[i-1].v)*100 : 100;
        return (
          <div key={d.label}>
            <div style={{display:"flex", justifyContent:"space-between", alignItems:"baseline", marginBottom:4}}>
              <span style={{fontSize:12.5, color:"var(--ink-2)", fontWeight:500}}>{d.label}</span>
              <span className="num" style={{fontSize:12, color:"var(--ink)"}}>{d.v.toLocaleString()}</span>
            </div>
            <div style={{height:24, background:"var(--surface-2)", borderRadius:3, overflow:"hidden", position:"relative"}}>
              <div style={{
                width: w + "%", height:"100%",
                background:"var(--accent)", opacity: 0.85 - i*0.1,
                display:"flex", alignItems:"center", paddingLeft:8
              }}>
                {i>0 && <span style={{fontFamily:"var(--font-mono)", fontSize:10, color:"var(--paper)"}}>{conv.toFixed(1)}%</span>}
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
};

const CohortGrid = ({cohorts}) => {
  const cols = Math.max(...cohorts.map(c => c.row.length), 1);
  const cell = 36, hgap = 2, vgap = 2;
  return (
    <div>
      <div style={{display:"grid", gridTemplateColumns:`100px 60px repeat(${cols}, ${cell}px)`, columnGap:hgap, rowGap:vgap}}>
        <div className="muted" style={{fontFamily:"var(--font-mono)", fontSize:10, textAlign:"left", padding:"0 4px"}}>Cohort</div>
        <div className="muted" style={{fontFamily:"var(--font-mono)", fontSize:10, textAlign:"right", padding:"0 4px"}}>Size</div>
        {Array.from({length:cols}, (_,i)=> (
          <div key={i} className="muted" style={{fontFamily:"var(--font-mono)", fontSize:10, textAlign:"center"}}>M{i}</div>
        ))}

        {cohorts.map((c,ri)=>(
          <React.Fragment key={c.month}>
            <div style={{fontFamily:"var(--font-mono)", fontSize:11, color:"var(--ink-2)", display:"flex", alignItems:"center", padding:"0 4px"}}>{c.month}</div>
            <div className="num" style={{fontSize:11, textAlign:"right", color:"var(--ink-3)", display:"flex", alignItems:"center", justifyContent:"flex-end", padding:"0 4px"}}>{c.sized.toLocaleString()}</div>
            {Array.from({length:cols}, (_,ci)=> {
              const v = c.row[ci];
              if (v == null) return <div key={ci} style={{height:24, background:"var(--surface-2)", borderRadius:2, opacity:0.4}}/>;
              const intensity = Math.max(0.08, v);
              return (
                <div key={ci} style={{
                  height:24, background:"var(--accent)", opacity: intensity,
                  borderRadius:2,
                  display:"grid", placeItems:"center",
                  fontFamily:"var(--font-mono)", fontSize:10,
                  color: intensity > 0.5 ? "var(--paper)" : "var(--ink)",
                }}>{Math.round(v*100)}</div>
              );
            })}
          </React.Fragment>
        ))}
      </div>
    </div>
  );
};

window.AnalyticsPage = AnalyticsPage;
