// Reusable SegmentChart - core visualization for any segment-keyed table
// Modes:
//   - 'column'  : vertical bar per segment (one metric at a time, toggle if multiple)
//   - 'stacked' : 100% horizontal bar per segment showing share-of-whole
// Plus a Chart/Table mode toggle on every card.

function SegmentChart({
  title,
  subtitle,
  segments,         // array of segment objects (canonical order)
  metrics,          // [{ key, label, value: (s)=>num, format: 'num'|'idr'|'pct'|'mins'|'days', share?: (s, allTotal)=>num }]
  leadingMetrics,   // optional metrics rendered before stacked columns
  mode = 'column',  // 'column' | 'stacked'
  stackKeys,        // for stacked mode: [{ key, label, color, value: (s)=>num }]
  onSelect,         // segment click handler
  showTotal = true, // show total in header
  totalFn,          // (segments) => string label for total
  defaultMetric,    // optional default metric key
  defaultView,      // 'chart' | 'table' (default 'table')
  showUnitToggle = false, // for stacked: toggle table cells between % and absolute count
  showGrandTotal = false, // append a Grand Total row in table view
  showTotalColumn = true, // show total column in stacked table mode
  grandTotalOverride, // for stacked: { pct: [..], total: number } — overrides computed values
  highlightTopN = null, // for stacked tables, highlight top N values
  highlightModeDefault = 'row', // 'row' | 'col'
  showHighlightToggle = false,
  stackNumFormat = 'num', // 'num' | 'k' — format for absolute values in stacked table
  valuesAreRatios = false, // when true, values are already ratios (0-1) — skip row normalization
}) {
  const [activeMetric, setActiveMetric] = React.useState(
    defaultMetric || (metrics ? metrics[0].key : null)
  );
  const [view, setView] = React.useState(defaultView || 'table'); // 'chart' | 'table'
  const [unit, setUnit] = React.useState('pct'); // 'pct' | 'num'
  const [hlMode, setHlMode] = React.useState(highlightModeDefault);

  const metric = metrics ? metrics.find(m => m.key === activeMetric) || metrics[0] : null;

  const colTops = React.useMemo(() => {
    if (!highlightTopN || hlMode !== 'col' || mode !== 'stacked') return [];
    return stackKeys.map(k => {
      const vals = segments.filter(s => s.key !== 'Outlier').map(s => {
        const tot = stackKeys.reduce((sum, sk) => sum + (sk.value(s) || 0), 0);
        const v = k.value(s) || 0;
        const pct = valuesAreRatios ? v : (tot > 0 ? v / tot : 0);
        return { key: s.key, v: pct };
      });
      vals.sort((a,b) => b.v - a.v);
      return vals.slice(0, highlightTopN).map(x => x.key);
    });
  }, [segments, stackKeys, highlightTopN, hlMode, mode, valuesAreRatios]);

  const colFormatters = React.useMemo(() => {
    if (!metrics) return {};
    const formatters = {};
    metrics.forEach(m => {
      const vals = segments.map(s => m.value(s));
      formatters[m.key] = fmt.columnFormatter(vals, m.format);
    });
    return formatters;
  }, [segments, metrics]);

  const leadingFormatters = React.useMemo(() => {
    if (!leadingMetrics) return {};
    const formatters = {};
    leadingMetrics.forEach(m => {
      const vals = segments.map(s => m.value(s));
      formatters[m.key] = fmt.columnFormatter(vals, m.format);
    });
    return formatters;
  }, [segments, leadingMetrics]);

  function fmtVal(v, format) {
    if (typeof v === 'string') return v;
    if (v == null || isNaN(v)) return '—';
    switch (format) {
      case 'idr':  return fmt.idr(v);
      case 'num':  return fmt.num(v);
      case 'int':  return fmt.int(v);
      case 'pct':  return fmt.pct(v, 1);
      case 'pctRaw': return fmt.pctRaw(v, 1);
      case 'mins': return v.toFixed(1) + 'm';
      case 'days': return v.toFixed(1) + 'd';
      case 'count': return Math.round(v).toLocaleString();
      case 'dec1': return v.toFixed(1);
      case 'dec2': return v.toFixed(2);
      default:     return Math.round(v).toLocaleString();
    }
  }

  // ---------- Compute totals & shares ----------
  let totalLabel = null;
  if (showTotal) {
    if (totalFn) totalLabel = totalFn(segments);
    else if (mode === 'column' && metric) {
      const total = segments.reduce((s, x) => s + (metric.value(x) || 0), 0);
      totalLabel = `Total: ${fmtVal(total, metric.format)}`;
    }
  }

  // ---------- TABLE VIEW ----------
  const tableView = (
    <div className="seg-chart-table-wrap" style={{ overflowX: 'auto' }}>
      <table className="seg-chart-table" style={{ whiteSpace: 'nowrap' }}>
        <thead>
          <tr>
            <th>Segment</th>
            {mode === 'column' && metrics && metrics.map(m => (
              <th key={m.key} style={{ textAlign: 'right', width: m.width }}>{m.label}</th>
            ))}
            {leadingMetrics && leadingMetrics.map(m => (
              <th key={m.key} style={{ textAlign: 'right', width: m.width }}>{m.label}</th>
            ))}
            {mode === 'stacked' && stackKeys.map(k => (
              <th key={k.key} style={{ textAlign: 'right' }}>{k.label}</th>
            ))}
            {mode === 'stacked' && showTotalColumn && <th style={{ textAlign: 'right' }}>Total</th>}
          </tr>
        </thead>
        <tbody>
          {segments.map((s) => (
            <tr key={s.key}>
              <td style={{ backgroundColor: SEG_PASTEL_COLORS[s.key] }}>
                <div className="seg-chart-table-name">
                  <div className="seg-chart-swatch" style={{ background: SEG_COLORS[s.key] }} />
                  {s.key}
                </div>
              </td>
              {mode === 'column' && metrics && metrics.map(m => {
                const fmtr = colFormatters[m.key];
                return <td key={m.key} className="num">{fmtr ? fmtr(m.value(s)) : fmtVal(m.value(s), m.format)}</td>;
              })}
              {leadingMetrics && leadingMetrics.map(m => {
                const fmtr = leadingFormatters[m.key];
                return <td key={m.key} className="num">{fmtr ? fmtr(m.value(s)) : fmtVal(m.value(s), m.format)}</td>;
              })}
              {mode === 'stacked' && (() => {
                const tot = stackKeys.reduce((sum, k) => sum + (k.value(s) || 0), 0);
                
                let topRowIndices = [];
                if (highlightTopN && hlMode === 'row' && s.key !== 'Outlier') {
                  const vals = stackKeys.map((k, i) => ({ v: k.value(s) || 0, i }));
                  vals.sort((a,b) => b.v - a.v);
                  topRowIndices = vals.slice(0, highlightTopN).map(x => x.i);
                }

                return (
                  <>
                    {stackKeys.map((k, i) => {
                      const v = k.value(s) || 0;
                      let isTop = false;
                      if (hlMode === 'row') isTop = topRowIndices.includes(i);
                      else if (hlMode === 'col') isTop = colTops[i] && colTops[i].includes(s.key);
                      
                      const style = isTop ? { fontWeight: '600', color: '#1e40af', background: '#eff6ff' } : {};
                      return (
                        <td key={k.key} className="num" style={style}>
                          {tot > 0 || valuesAreRatios
                            ? (unit === 'num' ? (stackNumFormat === 'k' ? fmt.k(v) : fmt.num(v)) : fmt.pct(valuesAreRatios ? v : v / tot, 1))
                            : '—'}
                        </td>
                      );
                    })}
                    {showTotalColumn && <td className="num">{stackNumFormat === 'k' ? fmt.k(tot) : fmt.num(tot)}</td>}
                  </>
                );
              })()}
            </tr>
          ))}
          {showGrandTotal && mode === 'stacked' && (() => {
            const totals = stackKeys.map(k =>
              segments.reduce((acc, s) => acc + (k.value(s) || 0), 0)
            );
            const grand = totals.reduce((a, b) => a + b, 0);
            const overridePct = grandTotalOverride && grandTotalOverride.pct;
            const overrideTotal = grandTotalOverride && grandTotalOverride.total;
            const totalUsersAll = segments.reduce((acc, s) => acc + (s.userCount || 0), 0);
            return (
              <tr className="grand-total-row">
                <td><strong>Grand Total</strong></td>
                {leadingMetrics && leadingMetrics.map(m => {
                  const fmtr = leadingFormatters[m.key];
                  return (
                    <td key={m.key} className="num">
                      <strong>{fmtr ? fmtr(m.grandTotal) : fmtVal(m.grandTotal, m.format)}</strong>
                    </td>
                  );
                })}
                {stackKeys.map((k, i) => (
                  <td key={k.key} className="num">
                    <strong>{
                      overridePct
                        ? (unit === 'num' && overrideTotal != null
                            ? (stackNumFormat === 'k' ? fmt.k(Math.round(overrideTotal * overridePct[i])) : fmt.num(Math.round(overrideTotal * overridePct[i])))
                            : fmt.pct(overridePct[i], 1))
                        : valuesAreRatios
                          ? fmt.pct(totalUsersAll > 0 ? segments.reduce((acc, s) => acc + (k.value(s) || 0) * (s.userCount || 0), 0) / totalUsersAll : 0, 1)
                          : (grand > 0
                            ? (unit === 'num' ? (stackNumFormat === 'k' ? fmt.k(totals[i]) : fmt.num(totals[i])) : fmt.pct(totals[i] / grand, 1))
                            : '—')
                    }</strong>
                  </td>
                ))}
                {showTotalColumn && <td className="num"><strong>{overrideTotal != null ? (stackNumFormat === 'k' ? fmt.k(overrideTotal) : fmt.num(overrideTotal)) : (stackNumFormat === 'k' ? fmt.k(grand) : fmt.num(grand))}</strong></td>}
              </tr>
            );
          })()}
          {showGrandTotal && mode === 'column' && (() => {
            return (
              <tr className="grand-total-row">
                <td><strong>Grand Total</strong></td>
                {leadingMetrics && leadingMetrics.map(m => (
                  <td key={m.key} className="num">
                    <strong>{fmtVal(m.grandTotal, m.format)}</strong>
                  </td>
                ))}
                {metrics && metrics.map(m => {
                  const tot = (m.grandTotal != null)
                    ? m.grandTotal
                    : segments.reduce((acc, s) => acc + (m.value(s) || 0), 0);
                  const fmtr = colFormatters[m.key];
                  return <td key={m.key} className="num"><strong>{fmtr ? fmtr(tot) : fmtVal(tot, m.format)}</strong></td>;
                })}
              </tr>
            );
          })()}
        </tbody>
      </table>
    </div>
  );

  // ---------- CHART VIEW ----------
  let chartView;
  if (mode === 'column' && metric) {
    const vals = segments.map(s => metric.value(s) || 0);
    const maxVal = Math.max(...vals, 0.0001);
    const minVal = Math.min(...vals, 0);
    const rangeVal = maxVal - minVal;
    const paddedMax = maxVal + (rangeVal * 0.15);
    const paddedMin = minVal < 0 ? minVal - (rangeVal * 0.15) : 0;
    const range = paddedMax - paddedMin;
    const chartHeight = 220;
    const zeroLineBottom = (Math.abs(paddedMin) / range) * chartHeight;
    const totalForShare = segments.reduce((s, x) => s + (metric.value(x) || 0), 0);

    chartView = (
      <div className="seg-col-chart" style={{ height: chartHeight + 60 }}>
        {segments.map((s) => {
          const v = metric.value(s) || 0;
          const isNegative = v < 0;
          const h = (Math.abs(v) / range) * chartHeight;
          const color = SEG_COLORS[s.key];
          const share = totalForShare > 0 ? v / totalForShare : 0;
          
          const gradient = isNegative 
            ? `linear-gradient(0deg, ${color}, ${color}cc)`
            : `linear-gradient(180deg, ${color}, ${color}cc)`;
          const borderRadius = isNegative ? '2px 2px 5px 5px' : '5px 5px 2px 2px';

          return (
            <div key={s.key} className="seg-col"
                 title={`${s.key} — ${fmtVal(v, metric.format)} (${fmt.pct(share,1)})`}>
              <div className="seg-col-stack" style={{ height: chartHeight, position: 'relative' }}>
                {minVal < 0 && (
                  <div style={{
                    position: 'absolute', left: -7, right: -7, height: 1,
                    bottom: `${zeroLineBottom}px`, background: 'var(--line-2)', zIndex: 0
                  }} />
                )}
                <div className="seg-col-value-top" style={{
                  position: 'absolute', left: 0, right: 0,
                  bottom: isNegative ? `${zeroLineBottom - h - 38}px` : `${zeroLineBottom + h + 6}px`,
                  marginBottom: 0
                }}>
                  <div className="seg-col-num">{fmtVal(v, metric.format)}</div>
                  <div className="seg-col-pct">{fmt.pct(share, 1)}</div>
                </div>
                <div className="seg-col-bar"
                     style={{ 
                       position: 'absolute', left: 0, right: 0,
                       height: `${h}px`, background: gradient, borderRadius,
                       bottom: isNegative ? `${zeroLineBottom - h}px` : `${zeroLineBottom}px`,
                       zIndex: 1
                     }} />
              </div>
              <div className="seg-col-label">{s.key}</div>
            </div>
          );
        })}
      </div>
    );
  } else if (mode === 'stacked') {
    chartView = (
      <div className="seg-stack-list">
        {segments.map((s) => {
          const tot = stackKeys.reduce((sum, k) => sum + (k.value(s) || 0), 0);
          return (
            <div key={s.key} className="seg-stack-row">
              <div className="seg-stack-label">
                <div className="seg-chart-swatch" style={{ background: SEG_COLORS[s.key] }} />
                <span>{s.key}</span>
              </div>
              <div className="seg-stack-bar">
                {(valuesAreRatios || tot > 0) ? stackKeys.map((k, i) => {
                  const v = k.value(s) || 0;
                  const pct = valuesAreRatios ? v * 100 : (v / tot) * 100;
                  if (pct < 0.5) return null;
                  return (
                    <div key={k.key} className="seg-stack-seg"
                         style={{ width: pct+'%', background: k.color }}
                         title={`${k.label}: ${fmt.pct(valuesAreRatios ? v : v/tot, 1)}`}>
                      {pct > 7 && <span className="seg-stack-num">{Math.round(pct)}%</span>}
                    </div>
                  );
                }) : <div className="seg-stack-empty">No data</div>}
              </div>
              <div className="seg-stack-total">{fmt.num(tot)}</div>
            </div>
          );
        })}
        <div className="seg-stack-legend">
          {stackKeys.map(k => (
            <div className="seg-stack-legend-item" key={k.key}>
              <div className="seg-chart-swatch" style={{ background: k.color }} />
              <span>{k.label}</span>
            </div>
          ))}
        </div>
      </div>
    );
  }

  // ---------- HEADER ----------
  return (
    <div className="card seg-col-card">
      <div className="card-head">
        <div>
          <div className="card-title">{title}</div>
          {subtitle && <div className="card-sub">{subtitle}</div>}
          {totalLabel && <div className="card-total">{totalLabel}</div>}
        </div>
        <div className="card-controls">
          {mode === 'column' && metrics && metrics.length > 1 && view === 'chart' && (
            <div className="metric-toggle">
              {metrics.map(m => (
                <button key={m.key}
                        className={activeMetric === m.key ? 'active' : ''}
                        onClick={() => setActiveMetric(m.key)}>{m.label}</button>
              ))}
            </div>
          )}
          {showUnitToggle && mode === 'stacked' && view === 'table' && (
            <div className="metric-toggle unit-toggle">
              <button className={unit === 'pct' ? 'active' : ''} onClick={() => setUnit('pct')}>%</button>
              <button className={unit === 'num' ? 'active' : ''} onClick={() => setUnit('num')}>#</button>
            </div>
          )}
          {showHighlightToggle && highlightTopN && view === 'table' && (
            <div className="metric-toggle unit-toggle" title="Highlight Top 2">
              <button className={hlMode === 'row' ? 'active' : ''} onClick={() => setHlMode('row')}>Row Top 2</button>
              <button className={hlMode === 'col' ? 'active' : ''} onClick={() => setHlMode('col')}>Col Top 2</button>
            </div>
          )}
          <div className="view-toggle" title={view === 'chart' ? 'Switch to table' : 'Switch to chart'}>
            <button className={view === 'chart' ? 'active' : ''} onClick={() => setView('chart')} aria-label="Chart view">
              <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
                <rect x="1" y="8" width="2.5" height="5" fill="currentColor"/>
                <rect x="5.75" y="4" width="2.5" height="9" fill="currentColor"/>
                <rect x="10.5" y="6" width="2.5" height="7" fill="currentColor"/>
              </svg>
            </button>
            <button className={view === 'table' ? 'active' : ''} onClick={() => setView('table')} aria-label="Table view">
              <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.4">
                <rect x="1" y="2" width="12" height="10" rx="1"/>
                <line x1="1" y1="6" x2="13" y2="6"/>
                <line x1="5" y1="2" x2="5" y2="12"/>
              </svg>
            </button>
          </div>
        </div>
      </div>
      {view === 'chart' ? chartView : tableView}
    </div>
  );
}

window.SegmentChart = SegmentChart;
