// DJ Mixes — individual mixes from across all collections, fed live from
// SoundCloud. Aggregates tracks from every set in window.RO_DJ_MIXES into one
// chronological list. Each row links directly to that mix's SoundCloud page.

const DJM_USER = 'htxedifice';

function djmSetUrl(slug) { return `https://soundcloud.com/${DJM_USER}/sets/${slug}`; }
function djmWidget(slug) {
  return 'https://w.soundcloud.com/player/?url=' + encodeURIComponent(djmSetUrl(slug)) +
    '&visual=false&show_artwork=false&show_user=false&auto_play=false';
}

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

function djmTrackArt(url) {
  if (!url) return null;
  return url.replace(/-large\./, '-t200x200.');
}

// Parse a mix number out of a title:
//   "Audratic Mix 12"             → 12
//   "Rachelle Mix #4 (2018.04.20)" → 4
//   "Episode 091"                  → 91
//   "Mix 06 — Spring 2017"         → 6
function parseMixNumber(title) {
  if (!title) return null;
  let m = title.match(/(?:mix|episode|ep\.?|set|vol(?:ume)?\.?)\s*#?\s*0*(\d{1,3})\b/i);
  if (m) return parseInt(m[1], 10);
  // Fall back to first 1-3 digit number that isn't a year (2000+ or 19xx).
  const matches = title.match(/\b\d{1,3}\b/g) || [];
  for (const tok of matches) {
    const n = parseInt(tok, 10);
    if (n >= 1 && n < 1000) return n;
  }
  return null;
}

// Reuse the title-date parser from Live (loaded earlier in the bundle).
function djmParseDate(title) {
  if (typeof parseTitleDate === 'function') return parseTitleDate(title);
  return null;
}

function djmFmtDate(parsed, fallback) {
  if (parsed && parsed.date) {
    const d = parsed.date;
    if (parsed.precision === 'year') return String(d.getUTCFullYear());
    if (parsed.precision === 'month') return `${d.getUTCFullYear()}.${String(d.getUTCMonth() + 1).padStart(2, '0')}`;
    return `${d.getUTCFullYear()}.${String(d.getUTCMonth() + 1).padStart(2, '0')}.${String(d.getUTCDate()).padStart(2, '0')}`;
  }
  if (fallback) {
    const d = new Date(fallback);
    if (!isNaN(d.getTime())) {
      return `${d.getUTCFullYear()}.${String(d.getUTCMonth() + 1).padStart(2, '0')}.${String(d.getUTCDate()).padStart(2, '0')}`;
    }
  }
  return '—';
}

// Standalone DJ mixes that aren't inside any of the SoundCloud sets in
// window.RO_DJ_MIXES. Deduped by permalink. Show under collection "Standalone".
const DJM_STATIC_EXTRAS = [
  {
    id: 'static-htx-2015',
    title: 'HTX (2015)',
    permalink_url: 'https://soundcloud.com/htxedifice/htx',
    duration: null,
    artwork_url: 'https://i1.sndcdn.com/artworks-8V547vIx35f5DQBB-noMRzg-t500x500.jpg',
    created_at: '2015-01-01T00:00:00Z',
  },
];
const DJM_STATIC_LABEL = 'Standalone';

function DJMixes({ t }) {
  const list = (typeof window !== 'undefined' && Array.isArray(window.RO_DJ_MIXES)) ? window.RO_DJ_MIXES : [];

  const [collection, setCollection] = React.useState('ALL');
  const [tracksByCat, setTracksByCat] = React.useState(() => {
    const m = {};
    for (const c of list) m[c.cat] = [];
    return m;
  });
  const [status, setStatus] = React.useState('loading'); // loading | live | offline

  const iframeRefs = React.useRef({});

  React.useEffect(() => {
    if (typeof SC === 'undefined' || !SC.Widget) {
      setStatus('offline');
      return;
    }
    const cleanups = [];
    let anyLive = false;
    for (const c of list) {
      const el = iframeRefs.current[c.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);
          setTracksByCat((prev) => ({ ...prev, [c.cat]: Array.from(seen.values()) }));
          anyLive = true;
          setStatus('live');
        });
      };
      widget.bind(SC.Widget.Events.READY, refresh);
      const polls = [800, 2000, 4500, 9000].map((d) => setTimeout(refresh, d));
      cleanups.push(() => polls.forEach(clearTimeout));
    }
    const giveUp = setTimeout(() => { if (!anyLive) setStatus('offline'); }, 13000);
    cleanups.push(() => clearTimeout(giveUp));
    return () => cleanups.forEach((fn) => fn());
  }, []);

  // Flatten + sort by parsed title-date (fallback to upload date). Static extras
  // (e.g. one-off mixes outside any SoundCloud set) are merged in too, deduped
  // by permalink so they don't double-up if added to a set later.
  const allMixes = React.useMemo(() => {
    const labelByCat = {};
    for (const c of list) labelByCat[c.cat] = c.label || c.era || c.slug;
    const out = [];
    const seenPerma = new Set();
    for (const c of list) {
      const arr = tracksByCat[c.cat] || [];
      for (const tr of arr) {
        if (tr.permalink_url) seenPerma.add(tr.permalink_url);
        out.push({
          id: tr.id,
          title: tr.title || '—',
          permalink: tr.permalink_url,
          duration: tr.duration || null,
          artwork: tr.artwork_url || null,
          createdAt: tr.created_at,
          collectionCat: c.cat,
          collectionLabel: labelByCat[c.cat],
        });
      }
    }
    for (const tr of DJM_STATIC_EXTRAS) {
      if (seenPerma.has(tr.permalink_url)) continue;
      out.push({
        id: tr.id,
        title: tr.title,
        permalink: tr.permalink_url,
        duration: tr.duration || null,
        artwork: tr.artwork_url || null,
        createdAt: tr.created_at,
        collectionCat: '__static__',
        collectionLabel: DJM_STATIC_LABEL,
      });
    }
    // Pure chronological sort: date DESC, with mix number DESC as tiebreaker
    // when dates are equal or year-only. Collection isn't a grouping key any
    // more — the COLLECTION column still tells you which set each mix is in,
    // and the Collection filter still narrows to one set.
    const dateFor = (x) => {
      const p = djmParseDate(x.title);
      if (p && p.date) return p.date.getTime();
      return Date.parse(x.createdAt) || 0;
    };
    const numFor = (x) => {
      const n = parseMixNumber(x.title);
      return n != null ? n : -Infinity;
    };
    out.sort((a, b) => {
      const dd = dateFor(b) - dateFor(a);
      if (dd !== 0) return dd;
      const nn = numFor(b) - numFor(a);
      if (nn !== 0) return nn;
      return 0;
    });
    return out;
  }, [tracksByCat]);

  const filtered = collection === 'ALL'
    ? allMixes
    : allMixes.filter((m) => m.collectionCat === collection);

  const totalAcrossAll = allMixes.length;

  return (
    <section id="dj-mixes" data-screen-label="05 DJ Mixes" className="sec sec-dj-mixes">
      <SectionHead num="05" title="DJ Mixes" sub="every mix · live from SoundCloud" />

      <div className="rel-bridges" aria-hidden="true">
        {list.map((c) => (
          <iframe
            key={c.cat}
            ref={(el) => { if (el) iframeRefs.current[c.cat] = el; }}
            title={`SoundCloud bridge for ${c.cat}`}
            src={djmWidget(c.slug)}
          />
        ))}
      </div>

      <div className="ro-controls">
        <div className="ro-count-row">
          <div className="ro-count">[ {filtered.length} MIXES{collection === 'ALL' && totalAcrossAll ? '' : ` / ${totalAcrossAll} TOTAL`} ]</div>
          <div className={`ro-status ro-status-${status}`}>
            {status === 'loading' ? '◐ SYNCING WITH SOUNDCLOUD'
              : status === 'live' ? '● LIVE FROM SOUNDCLOUD'
              : '○ OFFLINE'}
          </div>
        </div>
        <div className="ro-filters">
          <div className="ro-filter">
            <label className="ro-filter-lbl">Collection</label>
            <select value={collection} onChange={(e) => setCollection(e.target.value)}>
              <option value="ALL">All</option>
              {list.map((c) => (
                <option key={c.cat} value={c.cat}>{c.label} ({c.era})</option>
              ))}
            </select>
          </div>
        </div>
      </div>

      {filtered.length === 0 ? (
        <div className="scf-empty">{status === 'offline' ? 'Could not reach SoundCloud.' : 'Loading mixes…'}</div>
      ) : (
        <div className="ro-table">
          <div className="ro-row ro-row-djmix ro-head">
            <div>DATE</div>
            <div>COVER</div>
            <div>TITLE</div>
            <div>COLLECTION</div>
            <div>LEN</div>
            <div></div>
          </div>
          {filtered.map((m) => (
            <a key={`${m.collectionCat}-${m.id}`}
               className="ro-row ro-row-djmix"
               href={m.permalink}
               target="_blank"
               rel="noreferrer">
              <div className="num">{djmFmtDate(djmParseDate(m.title), m.createdAt)}</div>
              <div className="ro-thumb">
                {m.artwork
                  ? <img src={djmTrackArt(m.artwork)} alt="" loading="lazy" decoding="async" />
                  : <div className="ro-thumb-blank" />}
              </div>
              <div className="ro-title-cell">
                <span className="ro-title-name">{m.title}</span>
              </div>
              <div className="djmix-coll dim">{m.collectionLabel}</div>
              <div className="num">{djmFmtDur(m.duration)}</div>
              <div className="ro-arrow">↗</div>
            </a>
          ))}
        </div>
      )}

      <div className="ro-foot">
        <div className="ro-foot-bracket">
          ━━ FROM {list.length} COLLECTIONS / 2006 — present
        </div>
      </div>
    </section>
  );
}

window.DJMixes = DJMixes;
