// royalty-viz.jsx — Royalty Visualizer screen
// ─────────────────────────────────────────────────────────────────
// Dedicated full-screen surface for exploring royalty income across
// every dimension. Cross-filter store keeps all 9 charts in sync.
//
// Layout:
//   ╔═════════════════════════════════════════════════════════════╗
//   ║ Header · period · granularity · currency · data-source pill ║
//   ║ Filter chips (live, click ✕ to remove)                      ║
//   ║ KPI strip · gross / lines / sources / works / territories   ║
//   ╠═════════════════════════════════════════════════════════════╣
//   ║ Tab bar: Overview · Time · Composition · Geo · Long-tail    ║
//   ╠═════════════════════════════════════════════════════════════╣
//   ║ Chart panels per tab — click any element to cross-filter    ║
//   ╚═════════════════════════════════════════════════════════════╝
//
// Tweaks panel: granularity, currency, color palette, log/linear,
// chart density, focus mode (single chart fullscreen), data source.
//
// Exports: window.ScreenRoyaltyViz
// ─────────────────────────────────────────────────────────────────
(function () {
  if (typeof window === 'undefined' || !window.React) return;
  const _S = React.useState, _E = React.useEffect, _M = React.useMemo;

  function Mono({ children, upper, size, color, style, ...rest }) {
    return <span className={'ff-mono' + (upper?' upper':'')} style={{ fontSize: size||11, color: color||'var(--ink)', letterSpacing: upper?'.08em':0, ...style }} {...rest}>{children}</span>;
  }

  // ─── KPI cell ────────────────────────────────────────────────
  function Stat({ l, v, sub, tone, border }) {
    return (
      <div style={{ padding: '20px 24px', borderRight: border ? '1px solid var(--rule)' : 0, borderLeft: border ? '1px solid var(--rule)' : 0 }}>
        <Mono upper size={9} color="var(--ink-3)">{l}</Mono>
        <div className="ff-display" style={{ fontSize: 30, fontWeight: 600, letterSpacing: '-0.02em', marginTop: 6, color: tone || 'var(--ink)' }}>{v}</div>
        {sub && <Mono size={10} color="var(--ink-3)" style={{ marginTop: 4 }}>{sub}</Mono>}
      </div>
    );
  }

  // ─── Filter chips ────────────────────────────────────────────
  function FilterChips({ filter, onClear, onRemove }) {
    const items = Object.entries(filter || {}).flatMap(([dim, v]) => {
      if (Array.isArray(v)) return v.map(x => ({ dim, value: x }));
      return [{ dim, value: v }];
    });
    if (!items.length) return null;
    return (
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, padding: '12px 0', alignItems: 'center' }}>
        <Mono upper size={9} color="var(--ink-3)">FILTERED ·</Mono>
        {items.map((it, i) => (
          <button key={i} onClick={() => onRemove(it.dim, it.value)} title="Click to remove" style={{
            padding: '4px 10px', border: '1px solid var(--ink)', background: 'var(--ink)', color: 'var(--bg)',
            fontSize: 10, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6,
          }}>
            <span style={{ opacity: 0.7 }}>{window.RVE?.DIM_LABELS?.[it.dim] || it.dim}</span>
            <span>{it.value}</span>
            <span style={{ opacity: 0.7 }}>×</span>
          </button>
        ))}
        <button onClick={onClear} style={{ padding: '4px 10px', border: '1px solid var(--rule)', background: 'transparent', fontSize: 10, cursor: 'pointer' }}>Clear all</button>
      </div>
    );
  }

  // ─── Section card ────────────────────────────────────────────
  function Card({ title, sub, right, children, style }) {
    return (
      <section style={{ border: '1px solid var(--rule)', background: 'var(--bg)', ...style }}>
        <header style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', padding: '14px 18px', borderBottom: '1px solid var(--rule-soft)' }}>
          <div>
            <Mono upper size={9} color="var(--ink-3)">{title}</Mono>
            {sub && <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>{sub}</div>}
          </div>
          {right}
        </header>
        <div style={{ padding: 18, overflowX: 'auto' }}>{children}</div>
      </section>
    );
  }

  // ─── MAIN SCREEN ─────────────────────────────────────────────
  function ScreenRoyaltyViz({ go, payload }) {
    const PageHeader = window.PageHeader;
    const RVE = window.RVE;
    const RVCharts = window.RVCharts;

    const [tab, setTab] = _S(payload?.tab || 'overview');
    const [granularity, setGran] = _S('month');
    const [filter, setFilter] = _S(RVE?.getFilter() || {});
    const [_v, bump] = _S(0);
    const [focus, setFocus] = _S(null);

    _E(() => {
      if (!RVE) return;
      const unsub = RVE.subscribe((f) => { setFilter({ ...f }); bump(x => x + 1); });
      return unsub;
    }, []);

    if (!RVE || !RVCharts) {
      return <div style={{ padding: 40, textAlign: 'center' }}><Mono color="var(--ink-3)">Royalty viz engine not loaded.</Mono></div>;
    }

    const lines = _M(() => RVE.fetchLines(), [_v]);
    const ds = RVE.dataSource();

    // KPI summary
    const kpi = _M(() => {
      const sources = new Set(), works = new Set(), territories = new Set();
      let gross = 0;
      lines.forEach(l => { gross += l.gross; sources.add(l.source); works.add(l.work); if (l.territory) territories.add(l.territory); });
      return { gross, lines: lines.length, sources: sources.size, works: works.size, territories: territories.size };
    }, [lines]);

    function ToggleFn(dim) { return (val) => { RVE.toggleFilter(dim, val); }; }

    return (
      <div>
        {PageHeader && (
          <PageHeader
            eyebrow={['ROYALTIES', 'VISUALIZER', `DATA · ${ds.toUpperCase()}`, `${kpi.lines.toLocaleString()} LINES`]}
            title="see your money."
            highlight="see"
            sub={ds === 'real' ? 'Cross-filter across nine views. Every chart talks to every other.' : 'No statement inbox loaded — using synthetic data so the charts look populated. Drop a real statement in the Parser to switch.'}
          />
        )}

        {/* Granularity / data-source pills */}
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 8, flexWrap: 'wrap' }}>
          <Mono upper size={9} color="var(--ink-3)">GRANULARITY</Mono>
          {['month', 'quarter', 'year'].map(g => (
            <button key={g} onClick={() => setGran(g)} style={{
              padding: '4px 10px', border: '1px solid ' + (granularity === g ? 'var(--ink)' : 'var(--rule)'),
              background: granularity === g ? 'var(--ink)' : 'transparent', color: granularity === g ? 'var(--bg)' : 'var(--ink-2)',
              fontSize: 10, cursor: 'pointer', textTransform: 'uppercase', letterSpacing: '.06em',
            }}>{g}</button>
          ))}
          <span style={{ flex: 1 }} />
          <button onClick={() => { RVE.bustCache(); bump(x => x + 1); }} style={{ padding: '4px 10px', border: '1px solid var(--rule)', background: 'transparent', fontSize: 10, cursor: 'pointer' }}>↻ Refresh</button>
        </div>

        <FilterChips filter={filter} onClear={() => RVE.clearFilter()} onRemove={(d, v) => RVE.toggleFilter(d, v)}/>

        {/* KPI strip */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', borderTop: '1px solid var(--rule)', borderBottom: '1px solid var(--rule)', marginBottom: 24 }}>
          <Stat l="GROSS" v={RVCharts.fmt$(kpi.gross)}/>
          <Stat l="LINES" v={kpi.lines.toLocaleString()} border/>
          <Stat l="SOURCES" v={kpi.sources}/>
          <Stat l="WORKS" v={kpi.works.toLocaleString()} border/>
          <Stat l="TERRITORIES" v={kpi.territories}/>
        </div>

        {/* Tabs */}
        <div style={{ borderBottom: '1px solid var(--rule)', display: 'flex', gap: 0, marginBottom: 22 }}>
          {[
            { k: 'overview', l: 'Overview' },
            { k: 'time', l: 'Time' },
            { k: 'composition', l: 'Composition' },
            { k: 'geo', l: 'Geography' },
            { k: 'longtail', l: 'Long-tail' },
          ].map(t => (
            <button key={t.k} onClick={() => setTab(t.k)} style={{
              padding: '14px 22px', background: 'transparent',
              borderBottom: '2px solid ' + (tab === t.k ? 'var(--ink)' : 'transparent'),
              color: tab === t.k ? 'var(--ink)' : 'var(--ink-3)',
              fontSize: 13, fontWeight: tab === t.k ? 600 : 400, cursor: 'pointer',
            }}>{t.l}</button>
          ))}
        </div>

        {tab === 'overview' && <OverviewTab lines={lines} granularity={granularity} setFocus={setFocus}/>}
        {tab === 'time' && <TimeTab lines={lines} granularity={granularity}/>}
        {tab === 'composition' && <CompositionTab lines={lines}/>}
        {tab === 'geo' && <GeoTab lines={lines}/>}
        {tab === 'longtail' && <LongtailTab lines={lines}/>}

        {focus && <FocusOverlay onClose={() => setFocus(null)} title={focus.title} children={focus.children}/>}
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════════════
  // OVERVIEW — composite "everything at a glance"
  // ═══════════════════════════════════════════════════════════════
  function OverviewTab({ lines, granularity }) {
    const RVE = window.RVE, RVC = window.RVCharts;
    const ts = _M(() => RVE.timeSeries(lines, { granularity }), [lines, granularity]);
    const stack = _M(() => RVE.stackedBar(lines, 'sourceKind', { granularity }), [lines, granularity]);
    const tree = _M(() => RVE.treemap(lines, 'work', { limit: 30 }), [lines]);
    const par = _M(() => RVE.pareto(lines, 'work').rows.slice(0, 30), [lines]);

    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1.3fr 1fr', gap: 18 }}>
        <Card title="EARNINGS · OVER TIME" sub="Click a point to focus that period.">
          <RVC.TimeSeries points={ts} w={680} h={260} onPointClick={(p) => RVE.toggleFilter('period', p.key)} />
        </Card>
        <Card title="STACK · BY SOURCE TYPE">
          <RVC.StackedBar matrix={stack} w={520} h={260} onCellClick={(c) => RVE.toggleFilter('sourceKind', c.source)} />
          <Legend series={stack.series}/>
        </Card>
        <Card title="TOP WORKS · TREEMAP" sub="Area = $. Click a tile to focus." style={{ gridColumn: 'span 2' }}>
          <RVC.Treemap rows={tree} w={1200} h={340} onCellClick={(r) => RVE.toggleFilter('work', r.key)} />
        </Card>
        <Card title="PARETO · CONCENTRATION" sub="Top works ranked by $. Red = cumulative %." style={{ gridColumn: 'span 2' }}>
          <RVC.Pareto rows={par} w={1200} h={300} onBarClick={(r) => RVE.toggleFilter('work', r.key)} />
        </Card>
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════════════
  // TIME — granularity, MoM/YoY, cohorts
  // ═══════════════════════════════════════════════════════════════
  function TimeTab({ lines, granularity }) {
    const RVE = window.RVE, RVC = window.RVCharts;
    const [showYoY, setShowYoY] = _S(true);
    const ts = _M(() => RVE.timeSeries(lines, { granularity }), [lines, granularity]);
    const heat = _M(() => {
      const top = RVE.groupBy(lines, 'work', 16).rows.map(r => r.key);
      const subset = lines.filter(l => top.includes(l.work));
      return RVE.heatmap(subset, 'work', 'period');
    }, [lines]);
    const cohort = _M(() => RVE.cohort(lines), [lines]);
    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 18 }}>
        <Card
          title="EARNINGS · OVER TIME"
          right={<label style={{ fontSize: 10, color: 'var(--ink-3)', display: 'inline-flex', gap: 6, alignItems: 'center' }}><input type="checkbox" checked={showYoY} onChange={(e) => setShowYoY(e.target.checked)}/> show YoY</label>}
        >
          <RVC.TimeSeries points={ts} w={1200} h={300} showYoY={showYoY} onPointClick={(p) => RVE.toggleFilter('period', p.key)} />
        </Card>
        <Card title="WORK × PERIOD HEATMAP" sub="Top 16 works by total earnings.">
          <RVC.Heatmap rowKeys={heat.rowKeys.slice(0, 16)} colKeys={heat.colKeys} cells={heat.cells} w={1200} cellH={26}
            onCellClick={(c) => { RVE.toggleFilter('work', c.row); RVE.toggleFilter('period', c.col); }} />
        </Card>
        <Card title="COHORT · RELEASE-AGE × EARNINGS" sub="How does each release earn over its lifetime?">
          <RVC.Cohort cohorts={cohort} w={1200} maxAge={18} onCellClick={(c) => RVE.toggleFilter('release', c.release)} />
        </Card>
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════════════
  // COMPOSITION — sources, products, writers, sankey
  // ═══════════════════════════════════════════════════════════════
  function CompositionTab({ lines }) {
    const RVE = window.RVE, RVC = window.RVCharts;
    const sankey = _M(() => RVE.sankey(lines, ['sourceKind', 'work', 'writer']), [lines]);
    const bySource = _M(() => RVE.groupBy(lines, 'source', 12).rows, [lines]);
    const byProduct = _M(() => RVE.groupBy(lines, 'productType').rows, [lines]);
    const byWriter = _M(() => RVE.groupBy(lines, 'writer', 12).rows, [lines]);
    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 18 }}>
        <Card title="SANKEY · SOURCE → WORK → WRITER" sub="Top flows. Hover a band for $." >
          <RVC.Sankey nodes={sankey.nodes} links={sankey.links} w={1200} h={500} onNodeClick={(n) => {
            const dim = n.layer === 0 ? 'sourceKind' : n.layer === 1 ? 'work' : 'writer';
            RVE.toggleFilter(dim, n.name);
          }} />
        </Card>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 18 }}>
          <Card title="BY SOURCE · TOP 12">
            <RankedList rows={bySource} dim="source" />
          </Card>
          <Card title="BY PRODUCT TYPE">
            <RankedList rows={byProduct} dim="productType" />
          </Card>
          <Card title="BY WRITER · TOP 12">
            <RankedList rows={byWriter} dim="writer" />
          </Card>
        </div>
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════════════
  // GEO — choropleth + table
  // ═══════════════════════════════════════════════════════════════
  function GeoTab({ lines }) {
    const RVE = window.RVE, RVC = window.RVCharts;
    const territories = _M(() => RVE.choropleth(lines), [lines]);
    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 18 }}>
        <Card title="WORLD MAP · EARNINGS BY TERRITORY" sub="Bubble area = $. Click a bubble to focus.">
          <RVC.Choropleth rows={territories} w={1200} h={500} onTerritoryClick={(r) => RVE.toggleFilter('territory', r.key)} />
        </Card>
        <Card title="ALL TERRITORIES · RANKED">
          <RankedList rows={territories.slice(0, 30)} dim="territory" wide />
        </Card>
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════════════
  // LONG-TAIL — sparkline grid + pareto
  // ═══════════════════════════════════════════════════════════════
  function LongtailTab({ lines }) {
    const RVE = window.RVE, RVC = window.RVCharts;
    const sparks = _M(() => RVE.sparkGrid(lines, { dim: 'work', limit: 60 }), [lines]);
    const pareto = _M(() => RVE.pareto(lines, 'work').rows.slice(0, 50), [lines]);
    const eighty = pareto.findIndex(r => r.cumPct >= 0.8);

    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 18 }}>
        <Card title="PARETO · TOP 50 WORKS" sub={eighty >= 0 ? `Top ${eighty + 1} works (${(((eighty + 1) / pareto.length) * 100).toFixed(0)}%) earn 80% of revenue.` : 'Long-tail concentration view.'}>
          <RVC.Pareto rows={pareto} w={1200} h={320} onBarClick={(r) => RVE.toggleFilter('work', r.key)} />
        </Card>
        <Card title="PER-WORK SPARKLINES · TOP 60" sub="Each card is one work's earnings curve. Click to focus.">
          <RVC.SparkGrid items={sparks} columns={4} w={1200} rowH={56} onItemClick={(it) => RVE.toggleFilter('work', it.key)} />
        </Card>
      </div>
    );
  }

  // ─── Helpers ─────────────────────────────────────────────────
  function Legend({ series }) {
    const RVC = window.RVCharts;
    return (
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginTop: 12 }}>
        {series.map((s, i) => (
          <span key={s.key} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11 }}>
            <span style={{ width: 12, height: 8, background: RVC.colorFor(s.key, i) }}/>{s.key}
          </span>
        ))}
      </div>
    );
  }

  function RankedList({ rows, dim, wide }) {
    const RVE = window.RVE, RVC = window.RVCharts;
    const max = rows[0]?.value || 1;
    return (
      <div>
        {rows.map((r, i) => (
          <div key={r.key} onClick={() => RVE.toggleFilter(dim, r.key)} style={{
            display: 'grid', gridTemplateColumns: wide ? '40px 1fr 100px 60px' : '30px 1fr 80px',
            gap: 10, padding: '7px 0', alignItems: 'center', cursor: 'pointer',
            borderBottom: i < rows.length - 1 ? '1px solid var(--rule-soft)' : 0,
          }}>
            <Mono size={10} color="var(--ink-3)" style={{ textAlign: 'right' }}>{i + 1}</Mono>
            <div>
              <div style={{ fontSize: 12, fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.key}</div>
              <div style={{ height: 3, background: 'var(--rule-soft)', marginTop: 4 }}>
                <div style={{ height: 3, background: 'var(--ink)', width: ((r.value / max) * 100) + '%' }}/>
              </div>
            </div>
            <Mono size={11} style={{ textAlign: 'right' }}>{RVC.fmt$(r.value)}</Mono>
            {wide && <Mono size={10} color="var(--ink-3)" style={{ textAlign: 'right' }}>{(r.share * 100).toFixed(1)}%</Mono>}
          </div>
        ))}
      </div>
    );
  }

  function FocusOverlay({ title, children, onClose }) {
    return (
      <div role="dialog" onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 100 }}>
        <div onClick={(e) => e.stopPropagation()} style={{ background: 'var(--bg)', border: '1px solid var(--rule)', width: '90vw', maxWidth: 1400, maxHeight: '90vh', overflow: 'auto', padding: 28 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 18 }}>
            <Mono upper size={11}>{title}</Mono>
            <button onClick={onClose} style={{ padding: '6px 14px', border: '1px solid var(--rule)', background: 'transparent', fontSize: 11, cursor: 'pointer' }}>Close</button>
          </div>
          {children}
        </div>
      </div>
    );
  }

  window.ScreenRoyaltyViz = ScreenRoyaltyViz;
  console.log('[RoyaltyViz] loaded');
})();
