/* The 4 report pages — each takes the page state and renders its body. */

/* ============================================================
   PAGE 1 — Performance Over Time
   Four chart panels per report type.
   ============================================================ */
const PageOverTime = ({ reportType, granularity, comparison, changeMode, role, panelIds,
  onReorderPanels,
  datePreset, customDateLabel, viewerDisabled }) => {
  const panels = panelIds
    ? panelIds.map(id => reportType.chartPanels.find(p => p.id === id) || ALL_CHART_PANELS[id]).filter(Boolean)
    : reportType.chartPanels;

  /* RC-PAGE-021 — drag-to-reorder chart panels (mirrors scorecard DnD). */
  const [dragIdx, setDragIdx] = React.useState(null);
  const [hoverIdx, setHoverIdx] = React.useState(null);
  const canReorder = !viewerDisabled && typeof onReorderPanels === 'function';
  const handlePanelDrop = (to) => {
    if (!canReorder || dragIdx == null || dragIdx === to) { setDragIdx(null); setHoverIdx(null); return; }
    const ids = panels.map(p => p.id);
    const [moved] = ids.splice(dragIdx, 1);
    ids.splice(to, 0, moved);
    onReorderPanels(ids);
    setDragIdx(null); setHoverIdx(null);
  };

  /* RC-SEC-010 — split chart-scope from page-scope.
     When `followPage` is true, the section inherits page-level date from the page.
     Granularity (RC-PAGE-012) always lives here — chart-level concern. */
  const [followPage, setFollowPage] = React.useState(true);
  const [localDate, setLocalDate] = React.useState('l7');
  const [localGran, setLocalGran] = React.useState(granularity || 'day');
  const effectiveDate = followPage ? datePreset : localDate;
  const effectiveGran = localGran;  // RC-PAGE-012 — always chart-scope

  return (
    <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 14 }}>
      {/* RC-SEC-010 + RC-PAGE-012 — chart-scope controls */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap',
        padding: '9px 12px',
        background: followPage ? 'var(--rc-subtle)' : 'color-mix(in srgb, var(--rc-chart-1) 8%, var(--rc-card))',
        border: '1px solid var(--rc-border-soft)', borderRadius: 8,
      }}>
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11, color: 'var(--rc-text-sub)' }}>
          <Icon name="chart" size={11} />
          <span style={{ fontWeight: 500 }}>Chart scope:</span>
          <Segmented size="sm"
            tabs={[{ value: 'page', label: 'Follow page' }, { value: 'chart', label: 'Custom' }]}
            active={followPage ? 'page' : 'chart'}
            onChange={v => setFollowPage(v === 'page')} />
        </div>

        {/* Granularity — always on chart section (RC-PAGE-012) */}
        <div style={{ width: 1, height: 16, background: 'var(--rc-border)' }} />
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11, color: 'var(--rc-text-sub)' }}>
          <span style={{ fontWeight: 500 }}>Interval:</span>
          <Segmented size="sm"
            tabs={[{ value: 'day', label: 'Day' }, { value: 'week', label: 'Week' }, { value: 'month', label: 'Month' }]}
            active={localGran} onChange={v => { setLocalGran(v); window.rcTrack && window.rcTrack('RC-PAGE-012', 'granularity-change', { to: v }); }} />
        </div>

        {followPage ? (
          <span style={{ fontSize: 11, color: 'var(--rc-text-mute)', fontStyle: 'italic' }}>
            Date: page ({customDateLabel || (window.DATE_PRESETS && window.DATE_PRESETS.find(p => p.value === datePreset)?.label) || datePreset})
          </span>
        ) : (
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
            <SectionControls
              datePreset={localDate} setDatePreset={setLocalDate}
              comparison={comparison}
              viewerDisabled={viewerDisabled} />
          </div>
        )}
      </div>

      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 14,
      }}>
        {panels.map((panel, i) => {
          const isDragging = dragIdx === i;
          const isTarget = hoverIdx === i && dragIdx != null && dragIdx !== i;
          const insertBefore = isTarget && dragIdx > i;
          const insertAfter = isTarget && dragIdx < i;
          return (
            <div key={panel.id}
              draggable={canReorder}
              onDragStart={(e) => {
                if (!canReorder) return;
                setDragIdx(i);
                e.dataTransfer.effectAllowed = 'move';
                try {
                  const rect = e.currentTarget.getBoundingClientRect();
                  const ghost = e.currentTarget.cloneNode(true);
                  ghost.style.opacity = '0.7';
                  ghost.style.position = 'absolute';
                  ghost.style.top = '-2000px';
                  ghost.style.width = rect.width + 'px';
                  ghost.style.transform = 'rotate(-0.5deg) scale(0.98)';
                  ghost.style.boxShadow = '0 18px 48px -12px rgba(15,23,42,0.35)';
                  document.body.appendChild(ghost);
                  e.dataTransfer.setDragImage(ghost, rect.width / 2, 40);
                  setTimeout(() => ghost.remove(), 0);
                } catch (err) {}
              }}
              onDragOver={(e) => { if (dragIdx == null) return; e.preventDefault(); setHoverIdx(i); }}
              onDragLeave={() => { if (hoverIdx === i) setHoverIdx(null); }}
              onDrop={(e) => { e.preventDefault(); handlePanelDrop(i); }}
              onDragEnd={() => { setDragIdx(null); setHoverIdx(null); }}
              style={{
                position: 'relative',
                opacity: isDragging ? 0.4 : 1,
                transform: isDragging ? 'scale(0.99)' : 'scale(1)',
                cursor: canReorder ? (isDragging ? 'grabbing' : 'grab') : 'default',
                transition: 'opacity 0.12s, transform 0.12s',
              }}>
              {insertBefore && (
                <div style={{
                  position: 'absolute', left: -8, top: 6, bottom: 6, width: 3,
                  background: 'var(--rc-chart-1)', borderRadius: 2, zIndex: 2,
                  boxShadow: '0 0 0 4px color-mix(in srgb, var(--rc-chart-1) 18%, transparent)',
                }} />
              )}
              {insertAfter && (
                <div style={{
                  position: 'absolute', right: -8, top: 6, bottom: 6, width: 3,
                  background: 'var(--rc-chart-1)', borderRadius: 2, zIndex: 2,
                  boxShadow: '0 0 0 4px color-mix(in srgb, var(--rc-chart-1) 18%, transparent)',
                }} />
              )}
              <ChartPanel panel={panel} granularity={effectiveGran} comparison={comparison} />
            </div>
          );
        })}
      </div>
    </div>
  );
};

// Additional chart-panel definitions available via the "Available Charts" modal.
// (Superset matches CHART_PRESETS in customize_modals.jsx.)
// Metric ids are the canonical ones in fixtures.jsx / formatter.jsx.
const ALL_CHART_PANELS = {
  // ---- Retail ----
  sales:      { id: 'sales',      title: 'Sales',                   metrics: ['ops','totOrdItems','aovByOrdItem'] },
  units:      { id: 'units',      title: 'Units',                   metrics: ['unitsOrdered','asp','unitsPerOrdItem'] },
  traffic:    { id: 'traffic',    title: 'Traffic',                 metrics: ['sessions','pageViews','unitSessPct'] },
  coverage:   { id: 'coverage',   title: 'Coverage',                metrics: ['buyBoxPct','avgOfrCount'] },
  // ---- SP Ads ----
  perf:       { id: 'perf',       title: 'Performance',             metrics: ['spend','adSales','acos'] },
  reach:      { id: 'reach',      title: 'Awareness',               metrics: ['impressions','clicks','ctr'] },
  acq:        { id: 'acq',        title: 'Acquisitions',            metrics: ['cpa','aov','adOrders'] },
  eff:        { id: 'eff',        title: 'Efficiency',              metrics: ['cpc','convR'] },
  // ---- Combined ----
  salesmix:   { id: 'salesmix',   title: 'Sales Mix',               metrics: ['adSales','ops','adSalesPct'] },
  invest:     { id: 'invest',     title: 'Advertising Investment',  metrics: ['spend','acos','tacos'] },
  return:     { id: 'return',     title: 'Advertising Return',      metrics: ['cpa','aov','roas'] },
  efficiency: { id: 'efficiency', title: 'Efficiency',              metrics: ['adConvR','unitSessPct'] },
  // ---- Extra/derived ----
  salesad:    { id: 'salesad',    title: 'Sales vs. Ad Investment', metrics: ['ops','spend'] },
  trafficMix: { id: 'trafficMix', title: 'Traffic Mix',             metrics: ['sessions','pageViews','clicks'] },
  convFunnel: { id: 'convFunnel', title: 'Conversion Funnel',       metrics: ['impressions','clicks','convR'] },
};

const ChartPanel = ({ panel, granularity, comparison }) => {
  const [activeMetric, setActiveMetric] = React.useState(panel.metrics[0]);
  const values = window.series(activeMetric, 30);
  const priors = comparison !== 'none' ? window.priorPeriodSeries(activeMetric, 30) : null;
  const spec = METRIC_REGISTRY[activeMetric];
  const color = spec?.type === 'percent' ? 'var(--rc-chart-3)' :
                spec?.type === 'currency' ? 'var(--rc-chart-1)' : 'var(--rc-chart-2)';

  return (
    <Card>
      <div style={{ padding: '12px 14px 8px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: '1px solid var(--rc-border-soft)' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <h3 style={{ margin: 0, fontSize: 13, fontWeight: 600, fontFamily: 'Poppins', color: 'var(--rc-text)' }}>{panel.title}</h3>
          <span style={{ fontSize: 11, color: 'var(--rc-text-sub)', fontVariantNumeric: 'tabular-nums' }}>
            {formatValue(activeMetric, BASELINES[activeMetric])}
          </span>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
          <Segmented
            tabs={panel.metrics.map(m => ({ value: m, label: METRIC_LABELS[m] }))}
            active={activeMetric} onChange={setActiveMetric} size="sm" />
          <IconBtn name="download" title="Download" />
          <IconBtn name="expand" title="Expand" />
        </div>
      </div>
      <div style={{ padding: '8px 12px 12px' }}>
        <AreaChart values={values} priorValues={priors} color={color} height={170} showForecast={false} />
        <div style={{ display: 'flex', justifyContent: 'space-between', padding: '4px 36px 0', fontSize: 9, color: 'var(--rc-text-mute)' }}>
          {['Apr 01','Apr 05','Apr 09','Apr 13','Apr 17','Apr 21','Apr 25','Apr 29'].map(d => <span key={d}>{d}</span>)}
        </div>
      </div>
    </Card>
  );
};

/* ============================================================
   PAGE 2 — Performance Over Range (scorecards + item breakdown)
   ============================================================ */
const PageOverRange = ({ reportType, merchant, comparison, changeMode, setChangeMode, currency = 'USD', scorecardIds, onReorderScorecards, viewerDisabled }) => {
  const metricIds = scorecardIds || reportType.scorecards;
  return (
    <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 14 }}>
      <ScorecardsGrid metricIds={metricIds} comparison={comparison} changeMode={changeMode} currency={currency}
        onReorder={onReorderScorecards} disabled={viewerDisabled} />
      <ItemBreakdownTable reportType={reportType} comparison={comparison} changeMode={changeMode} setChangeMode={setChangeMode} />
    </div>
  );
};

const ColumnSortMenu = ({ col, sort, setSort, onClose, comparison }) => {
  const hasCompare = comparison && comparison !== 'none';
  const apply = (by, dir) => { setSort({ col, by, dir }); onClose(); };
  const clear = () => { setSort({ col: null, by: 'value', dir: 'desc' }); onClose(); };
  React.useEffect(() => {
    const h = (e) => { if (!e.target.closest('[data-col-menu]')) onClose(); };
    setTimeout(() => window.addEventListener('click', h), 0);
    return () => window.removeEventListener('click', h);
  }, []);
  const Opt = ({ by, dir, children, hint }) => {
    const on = sort.col === col && sort.by === by && sort.dir === dir;
    return (
      <button onClick={(e) => { e.stopPropagation(); apply(by, dir); }}
        style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          gap: 10, width: '100%', padding: '6px 9px', border: 0, borderRadius: 5,
          background: on ? 'var(--rc-hover)' : 'transparent', color: 'var(--rc-text)',
          cursor: 'pointer', fontFamily: 'inherit', fontSize: 12, textAlign: 'left',
        }}
        onMouseEnter={e => e.currentTarget.style.background = 'var(--rc-hover)'}
        onMouseLeave={e => e.currentTarget.style.background = on ? 'var(--rc-hover)' : 'transparent'}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
          <Icon name={dir === 'asc' ? 'arrowUp' : 'arrowDown'} size={10} color="var(--rc-text-sub)" />
          {children}
        </span>
        {hint && <span style={{ fontSize: 10, color: 'var(--rc-text-mute)', fontFamily: 'JetBrains Mono' }}>{hint}</span>}
      </button>
    );
  };
  return (
    <div data-col-menu onClick={e => e.stopPropagation()}
      style={{
        position: 'absolute', top: 'calc(100% + 6px)', right: 0, zIndex: 40,
        minWidth: 220, padding: 5,
        background: 'var(--rc-card)', border: '1px solid var(--rc-border)', borderRadius: 8,
        boxShadow: '0 10px 30px -8px rgba(15,23,42,0.25)', fontFamily: 'Inter',
      }}>
      <div style={{ padding: '6px 9px 4px', fontSize: 10, fontWeight: 600,
        color: 'var(--rc-text-mute)', letterSpacing: '0.05em', textTransform: 'uppercase' }}>
        Sort by value
      </div>
      <Opt by="value" dir="desc">High to low</Opt>
      <Opt by="value" dir="asc">Low to high</Opt>
      {hasCompare && (
        <>
          <div style={{ height: 1, background: 'var(--rc-border-soft)', margin: '5px 0' }} />
          <div style={{ padding: '4px 9px', fontSize: 10, fontWeight: 600,
            color: 'var(--rc-text-mute)', letterSpacing: '0.05em', textTransform: 'uppercase' }}>
            Sort by change
          </div>
          <Opt by="netDelta" dir="desc" hint="Δ">Biggest gain (net)</Opt>
          <Opt by="netDelta" dir="asc"  hint="Δ">Biggest drop (net)</Opt>
          <Opt by="pctDelta" dir="desc" hint="%">Biggest gain (%)</Opt>
          <Opt by="pctDelta" dir="asc"  hint="%">Biggest drop (%)</Opt>
        </>
      )}
      {sort.col === col && (
        <>
          <div style={{ height: 1, background: 'var(--rc-border-soft)', margin: '5px 0' }} />
          <button onClick={(e) => { e.stopPropagation(); clear(); }}
            style={{
              width: '100%', padding: '6px 9px', border: 0, borderRadius: 5,
              background: 'transparent', color: 'var(--rc-text-sub)',
              cursor: 'pointer', fontFamily: 'inherit', fontSize: 11.5, textAlign: 'left',
              display: 'inline-flex', alignItems: 'center', gap: 6,
            }}
            onMouseEnter={e => e.currentTarget.style.background = 'var(--rc-hover)'}
            onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
            <Icon name="x" size={10} /> Clear sort
          </button>
        </>
      )}
    </div>
  );
};

const ItemBreakdownTable = ({ reportType, comparison, changeMode, setChangeMode }) => {
  const defaultCols = reportType.itemColumns;

  /* RC-SEC-020 — column-menu sort: {col, by: 'value'|'netDelta'|'pctDelta', dir: 'asc'|'desc'} */
  const [sort, setSort] = React.useState({ col: null, by: 'value', dir: 'desc' });
  const [menuCol, setMenuCol] = React.useState(null);

  /* RC-SEC-021 — per-table column visibility + ordering (persisted per report type) */
  const colStoreKey = `rc-items-cols-${reportType.id}`;
  const [colState, setColState] = React.useState(() => {
    try {
      const raw = localStorage.getItem(colStoreKey);
      if (raw) {
        const parsed = JSON.parse(raw);
        // Drop columns that no longer exist in the report, keep ordering otherwise
        const valid = parsed.order.filter(c => defaultCols.includes(c));
        const missing = defaultCols.filter(c => !valid.includes(c));
        return { order: [...valid, ...missing], hidden: new Set((parsed.hidden || []).filter(c => defaultCols.includes(c))) };
      }
    } catch (e) {}
    return { order: defaultCols, hidden: new Set() };
  });
  React.useEffect(() => {
    // Reset to defaults when report type changes (order differs)
    try {
      const raw = localStorage.getItem(colStoreKey);
      if (!raw) setColState({ order: defaultCols, hidden: new Set() });
    } catch (e) {}
  }, [reportType.id]); // eslint-disable-line react-hooks/exhaustive-deps
  const persistColState = (next) => {
    setColState(next);
    try {
      localStorage.setItem(colStoreKey, JSON.stringify({ order: next.order, hidden: [...next.hidden] }));
    } catch (e) {}
  };
  const toggleHideCol = (col) => {
    const next = { order: colState.order, hidden: new Set(colState.hidden) };
    if (next.hidden.has(col)) next.hidden.delete(col); else next.hidden.add(col);
    persistColState(next);
  };
  const resetCols = () => persistColState({ order: defaultCols, hidden: new Set() });
  const [colPickerOpen, setColPickerOpen] = React.useState(false);
  const cols = colState.order.filter(c => !colState.hidden.has(c));

  /* Paginator wiring — 10 per page, 254 mock records */
  const totalRecords = 254;
  const pageSize = 10;
  const totalPages = Math.ceil(totalRecords / pageSize);
  const [page, setPage] = React.useState(1);

  /* Column drag-reorder within header */
  const [dragCol, setDragCol] = React.useState(null);
  const [dropTarget, setDropTarget] = React.useState(null);

  const rawRows = ASIN_FIXTURES.slice(0, 10).map((asin, i) => {
    const row = { asin: asin.asin, sku: asin.sku, name: asin.name, _idx: i };
    cols.forEach(col => {
      if (col === 'asin' || col === 'sku' || col === 'name' || col === 'campaign' || col === 'type') return;
      const base = BASELINES[col] ?? 100;
      const factor = 0.3 + (Math.sin(i * 1.7 + col.length) + 1) * 0.6;
      row[col] = base * factor * (1 - i * 0.06);
    });
    return row;
  });

  const rows = React.useMemo(() => {
    if (!sort.col) return rawRows;
    const arr = [...rawRows];
    const key = (r) => {
      const v = r[sort.col];
      if (sort.by === 'value') return v;
      const prior = v * (1 - 0.05 - (r._idx % 3) * 0.03);
      if (sort.by === 'netDelta') return v - prior;
      return prior !== 0 ? (v - prior) / prior : 0; // pctDelta
    };
    arr.sort((a, b) => (sort.dir === 'asc' ? 1 : -1) * (key(a) - key(b)));
    return arr;
  }, [rawRows, sort]);

  return (
    <Card>
      {/* Table toolbar */}
      <div style={{
        padding: '10px 14px', borderBottom: '1px solid var(--rc-border-soft)',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <h3 style={{ margin: 0, fontSize: 13, fontWeight: 600, fontFamily: 'Poppins' }}>Item Breakdown</h3>
          <span style={{ fontSize: 11, color: 'var(--rc-text-sub)' }}>{rows.length} items</span>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <Segmented
            tabs={[{ value: 'pct', label: '% Change' }, { value: 'net', label: 'Net Change' }]}
            active={changeMode} onChange={setChangeMode} size="sm" />
          <IconBtn name="download" title="Export items"
            onClick={() => {
              const run = () => {
                const sid = window.__rcToast.exportStarted({ scope: 'item breakdown' });
                setTimeout(() => {
                  window.__rcToast.dismiss(sid);
                  if (Math.random() < 0.6) {
                    window.__rcToast.exportSucceeded({
                      scope: 'items',
                      filename: `${reportType.id}_items.xlsx`,
                    });
                  } else {
                    window.__rcToast.exportFailed({ scope: 'item breakdown', onRetry: run });
                  }
                }, 900);
              };
              run();
            }} />
          <div style={{ position: 'relative' }}>
            <IconBtn name="grid" title="Show / hide columns"
              active={colPickerOpen}
              onClick={() => setColPickerOpen(!colPickerOpen)} />
            {colPickerOpen && (
              <>
                <div onClick={() => setColPickerOpen(false)}
                  style={{ position: 'fixed', inset: 0, zIndex: 40 }} />
                <div style={{
                  position: 'absolute', right: 0, top: 'calc(100% + 6px)', zIndex: 41,
                  background: 'var(--rc-card)', border: '1px solid var(--rc-border)',
                  borderRadius: 8, boxShadow: '0 12px 32px -8px rgba(15,23,42,0.22)',
                  minWidth: 240, padding: 6,
                }}>
                  <div style={{
                    fontSize: 10, fontWeight: 600, textTransform: 'uppercase',
                    letterSpacing: '0.05em', color: 'var(--rc-text-mute)',
                    padding: '4px 8px 6px',
                  }}>Columns · drag to reorder</div>
                  {colState.order.map((col, idx) => {
                    const label = col === 'asin' ? 'ASIN' :
                      col === 'sku' ? 'SKU' :
                      col === 'name' ? 'Product Name' :
                      col === 'campaign' ? 'Campaign' :
                      col === 'type' ? 'Type' :
                      METRIC_LABELS[col] || col;
                    const visible = !colState.hidden.has(col);
                    return (
                      <div key={col}
                        draggable
                        onDragStart={() => setDragCol(col)}
                        onDragOver={(e) => { e.preventDefault(); setDropTarget(col); }}
                        onDragEnd={() => { setDragCol(null); setDropTarget(null); }}
                        onDrop={(e) => {
                          e.preventDefault();
                          if (!dragCol || dragCol === col) return;
                          const next = [...colState.order];
                          const from = next.indexOf(dragCol);
                          const to = next.indexOf(col);
                          next.splice(from, 1);
                          next.splice(to, 0, dragCol);
                          persistColState({ order: next, hidden: colState.hidden });
                          setDragCol(null); setDropTarget(null);
                        }}
                        style={{
                          display: 'flex', alignItems: 'center', gap: 8, padding: '6px 8px',
                          borderRadius: 5, fontSize: 12, color: 'var(--rc-text)',
                          background: dropTarget === col ? 'var(--rc-hover)' : 'transparent',
                          borderTop: dropTarget === col && dragCol ? '2px solid var(--rc-green)' : '2px solid transparent',
                          opacity: dragCol === col ? 0.5 : 1,
                          cursor: 'grab',
                        }}>
                        <span style={{ color: 'var(--rc-text-mute)', display: 'inline-flex' }}>
                          <svg width="10" height="10" viewBox="0 0 16 16" fill="currentColor">
                            <circle cx="5" cy="4" r="1.2" /><circle cx="5" cy="8" r="1.2" /><circle cx="5" cy="12" r="1.2" />
                            <circle cx="11" cy="4" r="1.2" /><circle cx="11" cy="8" r="1.2" /><circle cx="11" cy="12" r="1.2" />
                          </svg>
                        </span>
                        <input type="checkbox" checked={visible}
                          onChange={() => toggleHideCol(col)}
                          style={{ cursor: 'pointer', accentColor: 'var(--rc-green)' }} />
                        <span style={{ flex: 1 }}>{label}</span>
                      </div>
                    );
                  })}
                  {(colState.hidden.size > 0 || colState.order.join('|') !== defaultCols.join('|')) && (
                    <button onClick={() => { resetCols(); setColPickerOpen(false); }} style={{
                      width: '100%', marginTop: 4, padding: '6px 8px', fontSize: 11,
                      background: 'transparent', border: 0,
                      borderTop: '1px solid var(--rc-border-soft)',
                      color: 'var(--rc-green-ink, var(--rc-green))',
                      cursor: 'pointer', fontFamily: 'inherit', fontWeight: 500, textAlign: 'left',
                    }}>Reset to default</button>
                  )}
                </div>
              </>
            )}
          </div>
        </div>
      </div>

      <div style={{ overflow: 'auto' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12, fontFamily: 'Inter', fontVariantNumeric: 'tabular-nums' }}>
          <thead>
            <tr>
              {cols.map((col, i) => {
                const isText = col === 'asin' || col === 'name' || col === 'campaign' || col === 'type' || col === 'sku';
                const label = col === 'asin' ? 'ASIN' :
                  col === 'sku' ? 'SKU' :
                  col === 'name' ? 'Product Name' :
                  col === 'campaign' ? 'Campaign' :
                  col === 'type' ? 'Type' :
                  METRIC_LABELS[col] || col;
                const isSorted = sort.col === col;
                const bgActive = isSorted
                  ? 'color-mix(in srgb, var(--rc-green) 8%, var(--rc-subtle))'
                  : 'var(--rc-subtle)';
                const handleHeaderClick = () => {
                  if (isText) return;
                  // Single-click toggles value-sort direction (most common action)
                  if (sort.col === col && sort.by === 'value') {
                    setSort({ col, by: 'value', dir: sort.dir === 'desc' ? 'asc' : 'desc' });
                  } else {
                    setSort({ col, by: 'value', dir: 'desc' });
                  }
                };
                return (
                  <th key={col} style={{
                    textAlign: isText ? 'left' : 'right',
                    padding: '10px 12px', fontSize: 11, fontWeight: 500,
                    color: isSorted ? 'var(--rc-text)' : 'var(--rc-text-sub)',
                    background: bgActive,
                    position: 'sticky', top: 0, whiteSpace: 'nowrap',
                    borderBottom: isSorted
                      ? '2px solid var(--rc-green)'
                      : '1px solid var(--rc-border)',
                    cursor: isText ? 'default' : 'pointer',
                    userSelect: 'none',
                  }}
                    onClick={handleHeaderClick}>
                    <span style={{
                      display: 'inline-flex', alignItems: 'center', gap: 4,
                      justifyContent: isText ? 'flex-start' : 'flex-end',
                      position: 'relative', width: '100%',
                    }}>
                      {label}
                      {isSorted && (
                        <span style={{
                          display: 'inline-flex', alignItems: 'center', gap: 2,
                          padding: '1px 4px', borderRadius: 3,
                          background: 'color-mix(in srgb, var(--rc-green) 18%, transparent)',
                          fontSize: 9, color: 'var(--rc-green-ink, var(--rc-green))',
                          fontWeight: 700, fontFamily: 'JetBrains Mono, monospace',
                        }}>
                          {sort.by === 'value' ? 'val' : sort.by === 'netDelta' ? 'Δ' : '%'}
                          <Icon name={sort.dir === 'asc' ? 'arrowUp' : 'arrowDown'} size={9} />
                        </span>
                      )}
                      {!isText && (
                        <button
                          onClick={(e) => {
                            e.stopPropagation();
                            setMenuCol(menuCol === col ? null : col);
                          }}
                          title="More sort options"
                          style={{
                            width: 14, height: 14, padding: 0, border: 0, borderRadius: 3,
                            background: 'transparent',
                            color: isSorted ? 'var(--rc-text)' : 'var(--rc-text-mute)',
                            cursor: 'pointer', display: 'inline-flex',
                            alignItems: 'center', justifyContent: 'center',
                          }}
                          onMouseEnter={e => e.currentTarget.style.background = 'var(--rc-hover)'}
                          onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
                          <Icon name="chevronDown" size={9} />
                        </button>
                      )}
                      {menuCol === col && !isText && (
                        <ColumnSortMenu col={col} sort={sort} setSort={setSort}
                          onClose={() => setMenuCol(null)} comparison={comparison} />
                      )}
                    </span>
                  </th>
                );
              })}
            </tr>
          </thead>
          <tbody>
            {rows.map((r, i) => (
              <tr key={i} style={{ borderBottom: '1px solid var(--rc-border-soft)' }}>
                {cols.map((col, ci) => {
                  if (col === 'asin') return (
                    <td key={col} style={tdCellL}>
                      <AsinCell asin={r.asin} name={r.name} marketplace="US" />
                    </td>
                  );
                  if (col === 'sku') return (
                    <td key={col} style={{ ...tdCellL, color: 'var(--rc-text-sub)', fontFamily: 'JetBrains Mono, monospace', fontSize: 11 }}>{r.sku}</td>
                  );
                  if (col === 'name') return (
                    <td key={col} style={{ ...tdCellL, color: 'var(--rc-text)', maxWidth: 240, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.name}</td>
                  );
                  if (col === 'campaign') {
                    const cf = (window.CAMPAIGN_FIXTURES || [])[i % 10] || { campaign: `SP | Auto | ${r.asin}`, type: 'SP' };
                    return (
                      <td key={col} style={tdCellL}>
                        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                          <Pill tone="default" size="sm">{cf.type}</Pill>
                          <span style={{ color: 'var(--rc-text)' }}>{cf.campaign}</span>
                        </span>
                      </td>
                    );
                  }
                  if (col === 'type') return <td key={col} style={tdCellL}><Pill tone="default" size="sm">SP</Pill></td>;
                  const val = r[col];
                  const prior = val * (1 - 0.05 - (i % 3) * 0.03);
                  const dir = changeDirection(col, val - prior);
                  const changeStr = comparison !== 'none' ? formatChange(col, val, prior, changeMode) : null;
                  return (
                    <td key={col} style={tdCellR}>
                      <div style={{ color: 'var(--rc-text)' }}>{formatValue(col, val)}</div>
                      {changeStr && <div style={{ fontSize: 10, marginTop: 2, color: dir === 'good' ? 'var(--rc-green-ink)' : dir === 'bad' ? 'var(--rc-negative)' : 'var(--rc-text-mute)', fontWeight: 500 }}>{changeStr}</div>}
                    </td>
                  );
                })}
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <div style={{ padding: '10px 14px', borderTop: '1px solid var(--rc-border-soft)',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        fontSize: 12, color: 'var(--rc-text-sub)' }}>
        <span>
          Records {(page - 1) * pageSize + 1} – {Math.min(page * pageSize, totalRecords)} of {totalRecords}
        </span>
        <Paginator page={page} totalPages={totalPages} onChange={setPage} />
      </div>
    </Card>
  );
};

const tdCellL = { padding: '10px 12px', textAlign: 'left', color: 'var(--rc-text-sub)', verticalAlign: 'top' };
const tdCellR = { padding: '10px 12px', textAlign: 'right', color: 'var(--rc-text-sub)', verticalAlign: 'top' };

const Paginator = ({ page = 1, totalPages = 26, onChange = () => {} }) => {
  const go = (p) => {
    const n = Math.max(1, Math.min(totalPages, p));
    if (n !== page) onChange(n);
  };
  // Build page buttons: 1, cur-1, cur, cur+1, …, last (with ellipses where needed)
  const buttons = [];
  const push = (v) => buttons.push(v);
  push('‹');
  const nums = new Set([1, 2, page - 1, page, page + 1, totalPages - 1, totalPages]);
  const sorted = [...nums].filter(n => n >= 1 && n <= totalPages).sort((a, b) => a - b);
  let last = 0;
  sorted.forEach(n => {
    if (n - last > 1) push('…');
    push(n);
    last = n;
  });
  push('›');
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 3 }}>
      {buttons.map((p, i) => {
        const isNum = typeof p === 'number';
        const isCur = isNum && p === page;
        const isEllipsis = p === '…';
        const isPrev = p === '‹';
        const isNext = p === '›';
        const disabled = isEllipsis || (isPrev && page === 1) || (isNext && page === totalPages);
        return (
          <button key={i}
            disabled={isEllipsis}
            onClick={() => {
              if (isPrev) go(page - 1);
              else if (isNext) go(page + 1);
              else if (isNum) go(p);
            }}
            style={{
              minWidth: 24, height: 24, padding: '0 6px', borderRadius: 5,
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              background: isCur ? 'var(--rc-ink)' : 'transparent',
              color: isCur ? '#fff' : disabled ? 'var(--rc-text-mute)' : 'var(--rc-text-sub)',
              border: isCur ? 'none' : '1px solid var(--rc-border)',
              fontSize: 11, fontWeight: 500,
              cursor: disabled ? 'default' : 'pointer',
              fontFamily: 'inherit',
              opacity: disabled && !isCur ? 0.5 : 1,
            }}>{p}</button>
        );
      })}
    </div>
  );
};

const SectionHeader = ({ title, subtitle }) => (
  <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
    <h2 style={{ margin: 0, fontSize: 15, fontWeight: 600, fontFamily: 'Poppins', letterSpacing: '-0.01em', color: 'var(--rc-text)' }}>{title}</h2>
    <span style={{ fontSize: 12, color: 'var(--rc-text-sub)' }}>{subtitle}</span>
  </div>
);

Object.assign(window, { PageOverTime, ChartPanel, PageOverRange, ItemBreakdownTable, Paginator, SectionHeader, ALL_CHART_PANELS });
