// Cortex — Research Queue page.
// The default landing page. Matches the original Streamlit version's flow:
// queue date → filters → table → drill-in. Dense, keyboard-friendly.

function FilterGroup({ label, items, selected, onToggle, count }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
        <Mono style={{ fontSize: 10, color: CX.faint, letterSpacing: '0.18em' }}>{label.toUpperCase()}</Mono>
        <Mono style={{ fontSize: 10, color: CX.veryFaint }}>{count}</Mono>
      </div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
        {items.map(i => (
          <Chip key={i} on={selected.has(i)} onClick={() => onToggle(i)}>{i}</Chip>
        ))}
      </div>
    </div>
  );
}

function RangeSlider({ label, min, max, value, onChange, suffix = '' }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
        <Mono style={{ fontSize: 10, color: CX.faint, letterSpacing: '0.18em' }}>{label.toUpperCase()}</Mono>
        <Mono style={{ fontSize: 11, color: CX.accent, letterSpacing: '0.06em' }}>{value}{suffix}</Mono>
      </div>
      <div style={{ position: 'relative', height: 28, display: 'flex', alignItems: 'center' }}>
        <div style={{ position: 'absolute', inset: '50% 0 auto 0', height: 1, background: CX.line }} />
        <div style={{ position: 'absolute', top: 'calc(50% - 0.5px)', left: 0, width: `${((value - min) / (max - min)) * 100}%`, height: 1, background: CX.accent }} />
        <input type="range" min={min} max={max} value={value}
          onChange={e => onChange(Number(e.target.value))}
          style={{ position: 'absolute', inset: 0, width: '100%', appearance: 'none', background: 'transparent', cursor: 'ew-resize', margin: 0 }} />
        <Mono style={{ position: 'absolute', left: 0, top: 20, fontSize: 9, color: CX.veryFaint }}>{min}</Mono>
        <Mono style={{ position: 'absolute', right: 0, top: 20, fontSize: 9, color: CX.veryFaint }}>{max}</Mono>
      </div>
    </div>
  );
}

// Inline mini-sparkline for momentum or score-over-time. Deterministic.
function Spark({ seed, w = 80, h = 18, color = CX.dim }) {
  const r = rng(seed);
  const pts = Array.from({ length: 24 }, () => r());
  const path = pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${(i / 23) * w} ${h - p * (h - 2) - 1}`).join(' ');
  return (
    <svg width={w} height={h} style={{ display: 'block' }}>
      <path d={path} fill="none" stroke={color} strokeWidth="1" />
    </svg>
  );
}

function rng(seed) {
  let s = (seed | 0) || 1;
  return () => { s = (s * 1664525 + 1013904223) | 0; return ((s >>> 0) % 10000) / 10000; };
}

function QueueTable({ rows, sortBy, sortDir, onSort, focusedTicker, onFocus }) {
  const cols = [
    { id: 'bucket',     label: 'BUCKET',    w: 130, align: 'left',  type: 'bucket',    help: 'primary_signal_bucket' },
    { id: 'rank',       label: '#',         w: 36,  align: 'right', type: 'rank',      help: 'bucket_rank' },
    { id: 'ticker',     label: 'TICKER',    w: 80,  align: 'left',  type: 'ticker' },
    { id: 'name',       label: 'COMPANY',   w: 200, align: 'left',  type: 'name' },
    { id: 'country',    label: 'CTRY',      w: 60,  align: 'left',  type: 'cc' },
    { id: 'sector',     label: 'SECTOR',    w: 150, align: 'left',  type: 'sector' },
    { id: 'quality',    label: 'QUALITY',   w: 100, align: 'right', type: 'score',     help: 'quality_score' },
    { id: 'value',      label: 'VALUE',     w: 100, align: 'right', type: 'score',     help: 'value_score' },
    { id: 'growth',     label: 'GROWTH',    w: 100, align: 'right', type: 'score',     help: 'growth_score' },
    { id: 'momentum',   label: 'MOMENTUM',  w: 100, align: 'right', type: 'score',     help: 'momentum_score' },
    { id: 'inflection', label: 'INFLECT.',  w: 100, align: 'right', type: 'score',     help: 'inflection_score' },
    { id: 'risk',       label: 'RISK',      w: 100, align: 'right', type: 'score-inv', help: 'risk_score' },
    { id: 'mcap_bucket', label: 'MCAP',     w: 80,  align: 'left',  type: 'tag',       help: 'market_cap_bucket' },
    { id: 'liquidity',  label: 'LIQ.',      w: 70,  align: 'left',  type: 'tag',       help: 'liquidity_bucket' },
    { id: 'flag',       label: 'FLAG',      w: 70,  align: 'right', type: 'flag' },
  ];
  const total = cols.reduce((a, c) => a + c.w, 0);
  return (
    <div style={{ border: `1px solid ${CX.line}`, background: CX.panel, overflow: 'hidden' }}>
      {/* header */}
      <div style={{ display: 'flex', borderBottom: `1px solid ${CX.line}`, fontFamily: CX.mono, fontSize: 10, color: CX.faint, letterSpacing: '0.1em' }}>
        {cols.map(c => (
          <div key={c.id} onClick={() => onSort(c.id)}
            style={{
              width: c.w, padding: '12px 10px', textAlign: c.align,
              cursor: 'pointer', display: 'flex', alignItems: 'center',
              justifyContent: c.align === 'right' ? 'flex-end' : 'flex-start',
              gap: 4,
              borderRight: '1px solid transparent',
            }}>
            <span style={{ color: sortBy === c.id ? CX.accent : CX.faint }}>{c.label}</span>
            {sortBy === c.id && <span style={{ color: CX.accent }}>{sortDir === 'desc' ? '↓' : '↑'}</span>}
            {c.help && <Help id={c.help} side={c.align === 'right' ? 'left' : 'right'} />}
          </div>
        ))}
      </div>
      {/* rows */}
      <div style={{ maxHeight: 540, overflowY: 'auto' }}>
        {rows.map((r, i) => {
          const focused = focusedTicker === r.ticker;
          return (
            <div key={`${r.security_id ?? r.ticker}-${r.bucket || 'none'}`} onClick={() => onFocus(r.ticker)}
              style={{
                display: 'flex', alignItems: 'center', cursor: 'pointer',
                background: focused ? CX.accentVery : (i % 2 ? 'transparent' : 'rgba(255,255,255,0.012)'),
                borderBottom: `1px solid ${CX.line}`,
                borderLeft: `2px solid ${focused ? CX.accent : 'transparent'}`,
              }}>
              {cols.map(c => {
                const v = r[c.id];
                const A = { textAlign: c.align, width: c.w, padding: '10px', display: 'flex', alignItems: 'center',
                  justifyContent: c.align === 'right' ? 'flex-end' : 'flex-start',
                  fontFamily: CX.mono, fontSize: 12, color: CX.text };
                if (c.type === 'bucket') {
                  const colors = { compounder: CX.accent, cheap_decent: CX.blue, inflection: CX.amber, pullback: CX.dim, danger: CX.red };
                  return <div key={c.id} style={A}>
                    <span style={{ color: colors[v], letterSpacing: '0.04em' }}>● {v}</span>
                  </div>;
                }
                if (c.type === 'rank') return <div key={c.id} style={{ ...A, color: CX.faint }}>{v}</div>;
                if (c.type === 'ticker') return <div key={c.id} style={{ ...A, color: CX.textHi }}>{v}</div>;
                if (c.type === 'name')   return <div key={c.id} style={{ ...A, color: CX.dim, fontFamily: CX.display }}>{v}</div>;
                if (c.type === 'cc') {
                  const code = { Sverige:'SE', Norge:'NO', Danmark:'DK', Finland:'FI', Island:'IS' }[v];
                  return <div key={c.id} style={A}>{code}</div>;
                }
                if (c.type === 'sector') return <div key={c.id} style={{ ...A, color: CX.dim, fontSize: 11 }}>{v}</div>;
                if (c.type === 'score' || c.type === 'score-inv') {
                  // For risk, flip color: high=bad
                  const display = c.type === 'score-inv' ? (
                    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                      <div style={{ width: 56, height: 4, background: CX.line, position: 'relative' }}>
                        <div style={{ position: 'absolute', inset: 0, width: `${v}%`, background: v > 70 ? CX.red : v > 40 ? CX.amber : CX.accent, opacity: 0.85 }} />
                      </div>
                      <Mono style={{ fontSize: 11, color: CX.text, width: 22, textAlign: 'right' }}>{v}</Mono>
                    </div>
                  ) : <Score v={v} />;
                  return <div key={c.id} style={A}>{display}</div>;
                }
                if (c.type === 'tag') {
                  const tone = v === 'liquid' || v === 'small_mid' ? CX.dim : v === 'thin' ? CX.amber : CX.dim;
                  return <div key={c.id} style={{ ...A, color: tone, fontSize: 11 }}>{v}</div>;
                }
                if (c.type === 'flag') {
                  const tone = v === 'NEW' || v === 'BUY' ? CX.accent : v === 'AVOID' ? CX.red : CX.faint;
                  return <div key={c.id} style={{ ...A, color: tone, fontSize: 11, letterSpacing: '0.08em' }}>{v || '—'}</div>;
                }
                return <div key={c.id} style={A}>{v}</div>;
              })}
            </div>
          );
        })}
      </div>
    </div>
  );
}

function DrillIn({ row }) {
  if (!row) {
    return (
      <div style={{ padding: '40px 0', textAlign: 'center', borderTop: `1px solid ${CX.line}` }}>
        <Mono style={{ fontSize: 11, color: CX.faint, letterSpacing: '0.12em' }}>SELECT A ROW TO DRILL IN ↑</Mono>
      </div>
    );
  }
  const fields = [
    [
      ['Bucket',     row.bucket,    null, 'primary_signal_bucket'],
      ['Rank',       `${row.rank} in bucket`, null, 'bucket_rank'],
      ['Country',    row.country,   null, null],
      ['Sector',     row.sector,    null, null],
    ],
    [
      ['Mcap',       `€ ${row.mcap_eur}M`, null, 'mcap_eur'],
      ['EV / EBIT',  row.ev_ebit,   null, 'ev_ebit'],
      ['FCF yield',  `${row.fcf_yield}%`, parseFloat(row.fcf_yield) >= 0 ? CX.accent : CX.red, 'fcf_yield'],
      ['Δ 30D',      `${row.thirty_d}%`,  parseFloat(row.thirty_d) >= 0 ? CX.accent : CX.red, 'thirty_d'],
    ],
    [
      ['Liquidity',  row.liquidity, null, 'liquidity_bucket'],
      ['Mcap bucket', row.mcap_bucket, null, 'market_cap_bucket'],
      ['Held',       row.held ? 'yes' : 'no', row.held ? CX.accent : CX.faint, null],
      ['Watchlist',  row.watch ? 'yes' : 'no', row.watch ? CX.amber : CX.faint, null],
    ],
  ];
  const scores = [
    ['Quality',    row.quality,    false, 'quality_score'],
    ['Value',      row.value,      false, 'value_score'],
    ['Growth',     row.growth,     false, 'growth_score'],
    ['Momentum',   row.momentum,   false, 'momentum_score'],
    ['Inflection', row.inflection, false, 'inflection_score'],
    ['Risk',       row.risk,       true,  'risk_score'],
  ];
  return (
    <div style={{ paddingTop: 32, borderTop: `1px solid ${CX.line}`, marginTop: 32 }}>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 24 }}>
        <div>
          <Mono style={{ fontSize: 10, color: CX.accent, letterSpacing: '0.18em' }}>DRILL IN · /Q.DRILL</Mono>
          <h3 style={{ fontFamily: CX.display, fontSize: 28, fontWeight: 400, letterSpacing: '-0.01em', margin: '10px 0 4px', color: CX.textHi }}>
            <Mono style={{ fontSize: 24, color: CX.text }}>{row.ticker}</Mono>
            <span style={{ marginLeft: 12, color: CX.dim, fontFamily: CX.display }}>{row.name}</span>
          </h3>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button style={btn(CX, 'ghost')}
            onClick={() => window.cortexGoTo?.({ page: 'tearsheet', ticker: row.ticker })}>
            Open tear sheet →
          </button>
          <button style={btn(CX, 'ghost')}
            onClick={() => window.cortexGoTo?.({ page: 'similar', ticker: row.ticker })}>
            Similar to…
          </button>
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1.2fr', gap: 24 }}>
        {fields.map((col, ci) => (
          <div key={ci} style={{ background: CX.panel, border: `1px solid ${CX.line}`, padding: '16px 18px' }}>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
              {col.map((f, i) => (
                <div key={i} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
                  <span style={{ display: 'inline-flex', alignItems: 'center' }}>
                    <Mono style={{ fontSize: 10, color: CX.faint, letterSpacing: '0.1em' }}>{f[0].toUpperCase()}</Mono>
                    {f[3] && <Help id={f[3]} />}
                  </span>
                  <Mono style={{ fontSize: 12, color: f[2] || CX.text }}>{f[1]}</Mono>
                </div>
              ))}
            </div>
          </div>
        ))}
        <div style={{ background: CX.panel, border: `1px solid ${CX.line}`, padding: '16px 18px' }}>
          <Mono style={{ fontSize: 10, color: CX.faint, letterSpacing: '0.1em' }}>SCORES</Mono>
          <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 10 }}>
            {scores.map((s, i) => (
              <div key={i} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                <span style={{ display: 'inline-flex', alignItems: 'center' }}>
                  <Mono style={{ fontSize: 11, color: CX.dim }}>{s[0]}</Mono>
                  <Help id={s[3]} />
                </span>
                {s[2] ? (
                  <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                    <div style={{ width: 60, height: 4, background: CX.line, position: 'relative' }}>
                      <div style={{ position: 'absolute', inset: 0, width: `${s[1]}%`, background: s[1] > 70 ? CX.red : s[1] > 40 ? CX.amber : CX.accent, opacity: 0.85 }} />
                    </div>
                    <Mono style={{ fontSize: 11, color: CX.text, width: 22, textAlign: 'right' }}>{s[1]}</Mono>
                  </div>
                ) : <Score v={s[1]} w={60} />}
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

function btn(C, kind) {
  const base = {
    appearance: 'none', cursor: 'pointer',
    padding: '8px 14px',
    fontFamily: C.mono, fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase',
    transition: 'background .12s',
  };
  if (kind === 'accent') return { ...base, background: C.accentDim, color: C.accent, border: `1px solid ${C.accent}` };
  return { ...base, background: 'transparent', color: C.dim, border: `1px solid ${C.lineHi}` };
}

function PageQueue() {
  // ── filter state
  const date = META.asof || 'no queue date';
  const [buckets, setBuckets]   = React.useState(new Set(BUCKETS));
  const [countries, setCountries] = React.useState(new Set(COUNTRIES));
  const [sectors, setSectors]   = React.useState(new Set(SECTORS));
  const [minQuality, setMinQuality] = React.useState(0);
  const [maxRisk, setMaxRisk]       = React.useState(100);
  const [sortBy, setSortBy]   = React.useState('rank');
  const [sortDir, setSortDir] = React.useState('asc');
  const [focused, setFocused] = React.useState(META.initial_ticker || ROWS[0]?.ticker || '');

  const toggle = (set, setSet) => (v) => {
    const n = new Set(set);
    if (n.has(v)) n.delete(v); else n.add(v);
    setSet(n);
  };

  const filtered = React.useMemo(() => {
    let xs = ROWS.filter(r =>
      buckets.has(r.bucket) &&
      countries.has(r.country) &&
      sectors.has(r.sector) &&
      r.quality >= minQuality &&
      r.risk    <= maxRisk
    );
    xs = [...xs].sort((a, b) => {
      const va = a[sortBy], vb = b[sortBy];
      const cmp = typeof va === 'number' ? va - vb : String(va).localeCompare(String(vb));
      return sortDir === 'desc' ? -cmp : cmp;
    });
    return xs;
  }, [buckets, countries, sectors, minQuality, maxRisk, sortBy, sortDir]);

  const focusedRow = filtered.find(r => r.ticker === focused) || filtered[0];

  return (
    <div style={{ padding: '32px 32px 64px', overflowY: 'auto', height: '100%' }}>
      {/* page header */}
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 24 }}>
        <div>
          <Mono style={{ fontSize: 10, color: CX.accent, letterSpacing: '0.18em' }}>01 · /Q.QUEUE</Mono>
          <h1 style={{ fontFamily: CX.display, fontSize: 40, fontWeight: 400, letterSpacing: '-0.02em', margin: '8px 0 0', color: CX.textHi }}>
            Research queue<span style={{ color: CX.accent }}>.</span>
          </h1>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
          <Mono style={{ fontSize: 11, color: CX.dim, letterSpacing: '0.06em' }}>
            queue date
          </Mono>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '6px 12px', border: `1px solid ${CX.line}`, background: CX.panel }}>
            <Mono style={{ fontSize: 12, color: CX.text }}>{date}</Mono>
            <Mono style={{ fontSize: 10, color: CX.faint }}>▾</Mono>
          </div>
          <button style={btn(CX, 'ghost')}>Export csv</button>
        </div>
      </div>

      {/* filters */}
      <div style={{ background: CX.panel, border: `1px solid ${CX.line}`, padding: '20px 22px', marginBottom: 24,
        display: 'grid', gridTemplateColumns: '1.3fr 1fr 1.6fr 0.9fr 0.9fr', gap: 32 }}>
        <FilterGroup label="Bucket"  items={BUCKETS}  selected={buckets}   onToggle={toggle(buckets,  setBuckets)}   count={`${buckets.size}/${BUCKETS.length}`}/>
        <FilterGroup label="Country" items={COUNTRIES} selected={countries} onToggle={toggle(countries, setCountries)} count={`${countries.size}/${COUNTRIES.length}`}/>
        <FilterGroup label="Sector"  items={SECTORS}  selected={sectors}   onToggle={toggle(sectors,  setSectors)}   count={`${sectors.size}/${SECTORS.length}`}/>
        <RangeSlider label="Min quality" min={0} max={100} value={minQuality} onChange={setMinQuality} />
        <RangeSlider label="Max risk"    min={0} max={100} value={maxRisk}    onChange={setMaxRisk} />
      </div>

      {/* meta row */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 12 }}>
        <Mono style={{ fontSize: 11, color: CX.dim, letterSpacing: '0.06em' }}>
          Showing <span style={{ color: CX.text }}>{filtered.length}</span> of {ROWS.length} rows · sorted by {sortBy} {sortDir}
        </Mono>
        <div style={{ display: 'flex', gap: 16, fontFamily: CX.mono, fontSize: 10, color: CX.faint, letterSpacing: '0.08em', alignItems: 'center' }}>
          <span style={{ display: 'inline-flex', alignItems: 'center' }}><span style={{ color: CX.accent }}>●</span>&nbsp;compounder<Help id="compounder_score" /></span>
          <span style={{ display: 'inline-flex', alignItems: 'center' }}><span style={{ color: CX.blue }}>●</span>&nbsp;cheap_decent<Help id="cheap_decent_score" /></span>
          <span style={{ display: 'inline-flex', alignItems: 'center' }}><span style={{ color: CX.amber }}>●</span>&nbsp;inflection<Help id="inflection_candidate_score" /></span>
          <span style={{ display: 'inline-flex', alignItems: 'center' }}><span style={{ color: CX.dim }}>●</span>&nbsp;pullback<Help id="quality_pullback_score" /></span>
          <span style={{ display: 'inline-flex', alignItems: 'center' }}><span style={{ color: CX.red }}>●</span>&nbsp;danger<Help id="danger_score" /></span>
        </div>
      </div>

      <QueueTable
        rows={filtered}
        sortBy={sortBy} sortDir={sortDir}
        onSort={(c) => { if (sortBy === c) setSortDir(sortDir === 'desc' ? 'asc' : 'desc'); else { setSortBy(c); setSortDir('desc'); } }}
        focusedTicker={focused} onFocus={setFocused}
      />

      <DrillIn row={focusedRow} />
    </div>
  );
}

window.PageQueue = PageQueue;
window.cortexBtn = btn;
window.Spark = Spark;
