// ml-screens-cluster.jsx — Catalog clustering tab + similarity viz
(function () {
  if (typeof window === 'undefined') return;
  const { useState: _S, useMemo: _M } = React;

  function ClusterMap({ result, activeId, onPick }) {
    const W = 760, H = 480;
    const points = result.points;
    const proj = result.proj;
    const PALETTE = ['#0a8754','#0070d6','#a35418','#a32a18','#5d3acc','#1a7a8a','#cc6f00','#7d2d6e'];

    const xs = proj.map(p => p[0]), ys = proj.map(p => p[1]);
    const xMin = Math.min(...xs), xMax = Math.max(...xs);
    const yMin = Math.min(...ys), yMax = Math.max(...ys);
    const px = (x) => 30 + ((x - xMin) / (xMax - xMin || 1)) * (W - 60);
    const py = (y) => H - 30 - ((y - yMin) / (yMax - yMin || 1)) * (H - 60);

    return (
      <svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{ display: 'block', background: 'var(--bg-2)' }}>
        <line x1="30" y1={H-30} x2={W-30} y2={H-30} stroke="var(--rule)" strokeWidth="1"/>
        <line x1="30" y1="30" x2="30" y2={H-30} stroke="var(--rule)" strokeWidth="1"/>
        <text x={W-30} y={H-12} fontSize="9" fill="var(--ink-3)" textAnchor="end" fontFamily="monospace">ENERGY × TEMPO →</text>
        <text x="30" y="22" fontSize="9" fill="var(--ink-3)" fontFamily="monospace">↑ VALENCE × ACOUSTIC</text>

        {/* points */}
        {result.assignments.map((c, i) => (
          <circle key={i} cx={px(proj[i][0])} cy={py(proj[i][1])} r={3.5}
            fill={PALETTE[c % PALETTE.length]} opacity="0.55"
            style={{ cursor: 'pointer' }}
            onClick={() => onPick(result.clusters[c])}/>
        ))}
        {/* centroids */}
        {result.clusters.map((c, i) => (
          <g key={i} style={{ cursor: 'pointer' }} onClick={() => onPick(c)}>
            <circle cx={px(c.proj2D[0])} cy={py(c.proj2D[1])} r={Math.max(8, Math.sqrt(c.size) * 1.6)}
              fill={PALETTE[i % PALETTE.length]} opacity={activeId === c.id ? 0.55 : 0.22}
              stroke={PALETTE[i % PALETTE.length]} strokeWidth="2"/>
            <text x={px(c.proj2D[0])} y={py(c.proj2D[1]) - Math.max(12, Math.sqrt(c.size) * 1.6 + 4)}
              fontSize="11" fontWeight="600" fill="var(--ink)" textAnchor="middle">{c.mood}</text>
            <text x={px(c.proj2D[0])} y={py(c.proj2D[1]) + Math.max(20, Math.sqrt(c.size) * 1.6 + 12)}
              fontSize="9" fill="var(--ink-3)" textAnchor="middle" fontFamily="monospace">{c.size} tracks</text>
          </g>
        ))}
      </svg>
    );
  }

  function ClusterCard({ cluster, active, onPick }) {
    const PALETTE = ['#0a8754','#0070d6','#a35418','#a32a18','#5d3acc','#1a7a8a','#cc6f00','#7d2d6e'];
    const idx = parseInt(cluster.id.slice(1), 10);
    const color = PALETTE[idx % PALETTE.length];
    return (
      <div onClick={() => onPick(cluster)} style={{
        padding: 16, border: '1px solid ' + (active ? color : 'var(--rule)'),
        borderLeft: '4px solid ' + color, cursor: 'pointer',
        background: active ? 'var(--bg-2)' : 'var(--bg)',
      }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: 6 }}>
          <span style={{ fontSize: 16, fontWeight: 600 }}>{cluster.mood}</span>
          <span style={{ fontSize: 11, color: 'var(--ink-3)' }}>· {cluster.genre}</span>
          <span style={{ flex: 1 }} />
          <span className="ff-mono num" style={{ fontSize: 11, color: 'var(--ink-3)' }}>{cluster.size}</span>
        </div>
        {cluster.useCases.length > 0 && (
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 8 }}>
            {cluster.useCases.map(u => (
              <span key={u} className="ff-mono upper" style={{
                fontSize: 8, padding: '2px 6px', border: '1px solid var(--rule)',
                color: 'var(--ink-2)', letterSpacing: '.1em',
              }}>{u}</span>
            ))}
          </div>
        )}
        <div style={{ marginTop: 10, fontSize: 11, color: 'var(--ink-3)', lineHeight: 1.5 }}>
          e.g. {cluster.examples.slice(0, 3).map(e => e.title).join(' · ')}
        </div>
      </div>
    );
  }

  function MLClusterTab() {
    const [k, setK] = _S(8);
    const [activeId, setActiveId] = _S(null);

    const result = _M(() => {
      if (!window.ClusterEngine) return null;
      return window.ClusterEngine.clusterCatalog({ k, limit: 300 });
    }, [k]);

    if (!result) return <div style={{ padding: 40 }}>Cluster engine not loaded.</div>;
    const active = result.clusters.find(c => c.id === activeId);

    return (
      <div>
        <div style={{ padding: '0 0 18px', display: 'flex', alignItems: 'baseline', gap: 14 }}>
          <div className="ff-mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '.14em' }}>CATALOG CLUSTERING · K-MEANS · AUDIO + METADATA</div>
          <span style={{ flex: 1 }} />
          <span className="ff-mono upper" style={{ fontSize: 9, color: 'var(--ink-3)', letterSpacing: '.12em' }}>K=</span>
          {[5, 6, 8, 10, 12].map(opt => (
            <button key={opt} onClick={() => { setK(opt); setActiveId(null); }} className="ff-mono num" style={{
              padding: '6px 10px', border: 0,
              background: k === opt ? 'var(--ink)' : 'transparent',
              color: k === opt ? 'var(--bg)' : 'var(--ink-2)',
              fontSize: 11, fontWeight: 600, cursor: 'pointer',
            }}>{opt}</button>
          ))}
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 360px', gap: 24 }}>
          <div style={{ border: '1px solid var(--rule)' }}>
            <ClusterMap result={result} activeId={activeId} onPick={(c) => setActiveId(c.id)} />
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8, maxHeight: 480, overflowY: 'auto' }}>
            {result.clusters.map(c => <ClusterCard key={c.id} cluster={c} active={c.id === activeId} onPick={(x) => setActiveId(x.id)} />)}
          </div>
        </div>

        {active && (
          <div style={{ marginTop: 28, padding: 20, border: '1px solid var(--rule)', background: 'var(--bg-2)' }}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, marginBottom: 14 }}>
              <span className="ff-mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '.12em' }}>CLUSTER {active.id} · {active.size} TRACKS</span>
              <span style={{ flex: 1 }} />
              <button style={{ padding: '7px 12px', border: '1px solid var(--ink)', background: 'var(--ink)', color: 'var(--bg)', fontSize: 11, fontWeight: 600, cursor: 'pointer' }}>EXPORT TO PLAYLIST</button>
              <button style={{ padding: '7px 12px', border: '1px solid var(--rule)', background: 'transparent', fontSize: 11, fontWeight: 600, cursor: 'pointer' }}>BULK-TAG ALL</button>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: 10 }}>
              {active.members.slice(0, 24).map(m => (
                <div key={m.rec.id} onClick={() => window.dispatchEvent(new CustomEvent('astro-open-recording', { detail: { id: m.rec.id }}))}
                  style={{ padding: 10, background: 'var(--bg)', border: '1px solid var(--rule-soft)', cursor: 'pointer' }}>
                  <div style={{ fontSize: 12, fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.rec.title}</div>
                  <div style={{ fontSize: 10, color: 'var(--ink-3)', marginTop: 2 }}>{m.rec.artist}</div>
                </div>
              ))}
            </div>
          </div>
        )}
      </div>
    );
  }

  function ClusterScorecard({ rec }) {
    const tags = _M(() => {
      if (!window.ClusterEngine || !rec) return null;
      const cached = window.__CLUSTER_RESULT_CACHE;
      let res = cached;
      if (!res) {
        res = window.ClusterEngine.clusterCatalog({ k: 8, limit: 300 });
        window.__CLUSTER_RESULT_CACHE = res;
      }
      return res.tagMap[rec.id];
    }, [rec && rec.id]);

    const similar = _M(() => window.ClusterEngine && rec ? window.ClusterEngine.similar(rec, { n: 6 }) : [], [rec && rec.id]);

    if (!tags) return null;
    return (
      <div style={{ border: '1px solid var(--rule)', background: 'var(--bg)' }}>
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--rule)' }}>
          <span className="ff-mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '.12em' }}>AUTO-TAGS · CLUSTER {tags.cluster}</span>
        </div>
        <div style={{ padding: 16, display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          <span className="ff-mono upper" style={{ padding: '4px 10px', background: 'var(--ink)', color: 'var(--bg)', fontSize: 10, letterSpacing: '.1em', fontWeight: 600 }}>{tags.mood}</span>
          <span className="ff-mono upper" style={{ padding: '4px 10px', border: '1px solid var(--ink)', fontSize: 10, letterSpacing: '.1em', fontWeight: 600 }}>{tags.genre}</span>
          {tags.useCases?.map(u => (
            <span key={u} className="ff-mono upper" style={{ padding: '4px 10px', border: '1px solid var(--rule)', color: 'var(--ink-2)', fontSize: 10, letterSpacing: '.1em' }}>{u}</span>
          ))}
        </div>
        <div style={{ padding: '0 16px 16px' }}>
          <div className="ff-mono upper" style={{ fontSize: 9, color: 'var(--ink-3)', letterSpacing: '.12em', marginBottom: 8 }}>SIMILAR TRACKS</div>
          {similar.slice(0, 5).map(s => (
            <div key={s.rec.id} onClick={() => window.dispatchEvent(new CustomEvent('astro-open-recording', { detail: { id: s.rec.id }}))}
              style={{ display: 'flex', justifyContent: 'space-between', padding: '7px 0', borderBottom: '1px solid var(--rule-soft)', cursor: 'pointer', fontSize: 12 }}>
              <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '70%' }}>{s.rec.title}</span>
              <span className="ff-mono num" style={{ color: 'var(--ink-3)' }}>{(s.sim * 100).toFixed(0)}%</span>
            </div>
          ))}
        </div>
      </div>
    );
  }

  window.MLClusterTab = MLClusterTab;
  window.ClusterScorecard = ClusterScorecard;
})();
