// Releases — discography fed live from SoundCloud.
//
// URLs come from window.RO_RELEASES (site/data/releases.js).
//   • oEmbed (CORS-friendly JSON): title, cover artwork, description.
//   • Widget API per release: track count + total runtime.
//
// Editing data/releases.js is the only thing required to add or remove a
// discography entry; everything else updates from the source.

const RELEASES_USER = 'htxedifice';
const RELEASES_USER_DISPLAY = 'HTXEdifice';

function setUrl(slug) { return `https://soundcloud.com/${RELEASES_USER}/sets/${slug}`; }
function oembedUrl(slug) { return `https://soundcloud.com/oembed?url=${encodeURIComponent(setUrl(slug))}&format=json`; }
function widgetUrl(slug) {
  return 'https://w.soundcloud.com/player/?url=' + encodeURIComponent(setUrl(slug)) +
    '&visual=false&show_artwork=false&show_user=false&auto_play=false';
}

function relStripAuthor(title) {
  if (!title) return '';
  return title.replace(/\s*by\s+HTXEdifice.*$/i, '').trim();
}

function fmtRelDate(d, fallbackYear) {
  if (d instanceof Date && !isNaN(d.getTime())) {
    return `${d.getUTCFullYear()}.${String(d.getUTCMonth() + 1).padStart(2, '0')}.${String(d.getUTCDate()).padStart(2, '0')}`;
  }
  return fallbackYear ? String(fallbackYear) : '—';
}

function fmtTotal(ms) {
  if (!ms || ms < 1000) return '—';
  const s = Math.round(ms / 1000);
  const m = Math.floor(s / 60);
  if (m >= 60) {
    const h = Math.floor(m / 60);
    const rm = m % 60;
    return `${h}:${String(rm).padStart(2, '0')}:00`;
  }
  const r = s % 60;
  return `${String(m).padStart(2, '0')}:${String(r).padStart(2, '0')}`;
}

// Upgrade SoundCloud's CDN image URL from -t500x500 to -t1080x1080 for sharper
// covers in the grid view.
function hiResArtwork(url, size = 't500x500') {
  if (!url) return null;
  return url.replace(/-t\d+x\d+\./, `-${size}.`);
}

function Releases({ t }) {
  const list = (typeof window !== 'undefined' && Array.isArray(window.RO_RELEASES)) ? window.RO_RELEASES : [];
  const [view, setView] = React.useState('list'); // list | grid
  const [hover, setHover] = React.useState(null);
  const [byCat, setByCat] = React.useState(() => {
    const m = {};
    for (const r of list) m[r.cat] = { ...r, title: null, thumbnail: null, description: null, tracks: null, lengthMs: null, status: 'loading' };
    return m;
  });

  // 1) oEmbed — fetch title + thumbnail + description for each release.
  React.useEffect(() => {
    let alive = true;
    Promise.allSettled(
      list.map((r) =>
        fetch(oembedUrl(r.slug))
          .then((res) => (res.ok ? res.json() : Promise.reject(res.status)))
          .then((data) => ({ cat: r.cat, ok: true, data }))
          .catch((err) => ({ cat: r.cat, ok: false, err }))
      )
    ).then((results) => {
      if (!alive) return;
      setByCat((prev) => {
        const next = { ...prev };
        for (const result of results) {
          const v = result.status === 'fulfilled' ? result.value : { ok: false };
          if (!v.ok) continue;
          const cur = next[v.cat];
          if (!cur) continue;
          next[v.cat] = {
            ...cur,
            title: relStripAuthor(v.data.title),
            thumbnail: v.data.thumbnail_url,
            description: v.data.description || '',
            status: 'oembed',
          };
        }
        return next;
      });
    });
    return () => { alive = false; };
  }, []);

  // 2) Widget API per release — fills in track count + total length.
  const iframeRefs = React.useRef({});

  React.useEffect(() => {
    if (typeof SC === 'undefined' || !SC.Widget) return;
    const cleanups = [];
    for (const r of list) {
      const el = iframeRefs.current[r.cat];
      if (!el) continue;
      const widget = SC.Widget(el);
      const seen = new Map();
      const refresh = () => {
        widget.getSounds((sounds) => {
          if (!sounds || !sounds.length) return;
          for (const s of sounds) seen.set(s.id, s);
          const arr = Array.from(seen.values());
          const total = arr.reduce((sum, s) => sum + (s.duration || 0), 0);
          const stamps = arr.map((s) => s.created_at).filter(Boolean).map((d) => Date.parse(d)).filter((n) => !isNaN(n));
          const releaseDate = stamps.length ? new Date(Math.min(...stamps)) : null;
          setByCat((prev) => {
            const cur = prev[r.cat];
            if (!cur) return prev;
            return { ...prev, [r.cat]: { ...cur, tracks: seen.size, lengthMs: total, releaseDate, status: 'live' } };
          });
        });
      };
      widget.bind(SC.Widget.Events.READY, refresh);
      const polls = [800, 2000, 4500].map((d) => setTimeout(refresh, d));
      cleanups.push(() => {
        polls.forEach(clearTimeout);
        try { widget.unbind(SC.Widget.Events.READY); } catch (e) { /* ignore */ }
      });
    }
    return () => cleanups.forEach((fn) => fn());
  }, []);

  // Newest first — same order as the URL list, reversed.
  const displayed = list.slice().reverse().map((r) => byCat[r.cat] || r);

  return (
    <section id="releases" data-screen-label="02 Releases" className="sec sec-releases">
      <SectionHead num="02" title="Releases" sub="discography · live from SoundCloud" />

      {/* Hidden Widget-API bridges, one per release. */}
      <div className="rel-bridges" aria-hidden="true">
        {list.map((r) => (
          <iframe
            key={r.cat}
            ref={(el) => { if (el) iframeRefs.current[r.cat] = el; }}
            title={`SoundCloud bridge for ${r.cat}`}
            src={widgetUrl(r.slug)}
          />
        ))}
      </div>

      <div className="rel-controls">
        <div className="rel-count">[ {list.length} ENTRIES ]</div>
        <div className="rel-views">
          <button data-on={view === 'list'} onClick={() => setView('list')}>LIST</button>
          <button data-on={view === 'grid'} onClick={() => setView('grid')}>GRID</button>
        </div>
      </div>

      {view === 'list' ? (
        <div className="rel-table">
          <div className="rel-row rel-head">
            <div>CAT</div>
            <div>TITLE</div>
            <div>FORMAT</div>
            <div>LABEL</div>
            <div>TRK</div>
            <div>LENGTH</div>
            <div>RELEASED</div>
            <div></div>
          </div>
          {displayed.map((r, i) => (
            <a key={r.cat}
               className="rel-row"
               href={setUrl(r.slug)}
               target="_blank"
               rel="noreferrer"
               onMouseEnter={() => setHover(i)}
               onMouseLeave={() => setHover(null)}>
              <div className="rel-cat">{r.cat}</div>
              <div className="rel-title">
                <div
                  className="rel-cover"
                  style={r.thumbnail ? { backgroundImage: `url(${r.thumbnail})`, backgroundSize: 'cover', backgroundPosition: 'center' } : undefined}
                >
                  {!r.thumbnail && <div className="rel-cover-blank" />}
                </div>
                <span className="rel-title-name">{r.title || '—'}</span>
              </div>
              <div>{r.format || '—'}</div>
              <div className="rel-label">{r.label || '—'}</div>
              <div>{r.tracks != null ? String(r.tracks).padStart(2, '0') : '—'}</div>
              <div className="num">{r.lengthMs != null ? fmtTotal(r.lengthMs) : '—'}</div>
              <div className="num">{fmtRelDate(r.releaseDate, r.year)}</div>
              <div className="rel-arrow">↗</div>
            </a>
          ))}
        </div>
      ) : (
        <div className="rel-grid">
          {displayed.map((r) => {
            const big = hiResArtwork(r.thumbnail, 't1080x1080');
            return (
              <a key={r.cat} className="rel-card" href={setUrl(r.slug)} target="_blank" rel="noreferrer">
                <div
                  className="rel-cover rel-cover-grid"
                  style={big ? { backgroundImage: `url(${big})`, backgroundSize: 'cover', backgroundPosition: 'center' } : undefined}
                >
                  {!r.thumbnail && <div className="rel-cover-blank" />}
                </div>
                <div className="rel-card-meta">
                  <div className="rel-card-cat">{r.cat} · {r.format || 'LP'}</div>
                  <div className="rel-card-title">{r.title || '—'}</div>
                  <div className="rel-card-sub">
                    {r.label || RELEASES_USER_DISPLAY} · {fmtRelDate(r.releaseDate, r.year)}
                    {r.tracks != null && r.lengthMs != null ? ` · ${r.tracks} tr · ${fmtTotal(r.lengthMs)}` : ''}
                  </div>
                </div>
              </a>
            );
          })}
        </div>
      )}

      <div className="rel-foot">
        <div className="rel-foot-bracket">
          ━━ FULL CATALOG AT
          <a href={`https://soundcloud.com/${RELEASES_USER}/albums`} target="_blank" rel="noreferrer">
            soundcloud.com/{RELEASES_USER}/albums
          </a>
          / {list.length} releases · {RELEASES_USER_DISPLAY}
        </div>
      </div>
    </section>
  );
}

window.Releases = Releases;
