// ============================================================
//  MISSION : INFECT — epideM:Ic  | components
// ============================================================

const { useState, useEffect, useRef, useMemo } = React;

// ---------- utils ----------
const fmt = (s) => {
  if (!isFinite(s) || s < 0) s = 0;
  const m = Math.floor(s / 60);
  const r = Math.floor(s % 60);
  return `${m}:${r.toString().padStart(2, "0")}`;
};

// ---------- ArtistCard: swaps when current verse changes ----------
function ArtistCard({ artist }) {
  const [shown, setShown] = useState(artist);
  const [glitch, setGlitch] = useState(false);

  useEffect(() => {
    if (!artist || shown?.id === artist?.id) return;
    setGlitch(true);
    const t1 = setTimeout(() => setShown(artist), 220);
    const t2 = setTimeout(() => setGlitch(false), 520);
    return () => { clearTimeout(t1); clearTimeout(t2); };
  }, [artist?.id]);

  if (!shown) {
    return (
      <div className="artist-card artist-card--empty">
        <div className="artist-card__label">NO SIGNAL</div>
        <div className="artist-card__scan" />
      </div>
    );
  }

  return (
    <div className={`artist-card ${glitch ? "is-glitch" : ""}`} key={shown.id}>
      <div className="artist-card__chrome">
        <span className="dot dot--red" />
        <span className="artist-card__chrome-label">SPEC.AGT — LIVE</span>
        <span className="artist-card__chrome-id">
          ID / {shown.callsign ?? shown.id.toUpperCase()}
        </span>
      </div>

      <div className="artist-card__body">
        <div className="artist-card__portrait">
          <div
            className="portrait-img"
            style={{ background: shown.portrait }}
            aria-label={`${shown.name} portrait`}
          >
            {shown.image && (
              <img
                className="portrait-photo"
                src={shown.image}
                alt={`${shown.name} portrait`}
                loading="lazy"
                onError={(e) => { e.currentTarget.style.display = "none"; }}
              />
            )}
            <div className="portrait-initials">{shown.initials}</div>
            <div className="portrait-grid" />
            <div className="portrait-scan" />
            <div className="portrait-target">
              <span className="t t-tl" /><span className="t t-tr" />
              <span className="t t-bl" /><span className="t t-br" />
            </div>
          </div>
          <div className="portrait-tags">
            <span className="tag tag--live"><span className="tag-dot" />ON AIR</span>
          </div>
        </div>

        <div className="artist-card__meta">
          <div className="artist-card__name" data-text={shown.name}>
            {shown.name}
          </div>
          <div className="artist-card__tagline">{shown.role}</div>

          <dl className="artist-card__stats">
            <div><dt>ORIGIN</dt><dd>{shown.origin}</dd></div>
            <div><dt>VERSE</dt><dd>{shown.verse}</dd></div>
            <div><dt>STATUS</dt><dd className="pulse">INFECTED</dd></div>
          </dl>

          <div className="artist-card__links">
            {shown.links.map((l) => (
              <a key={l.label} href={l.url} target="_blank" rel="noreferrer" className="alink">
                <span className="alink__i">{l.icon}</span>
                <span className="alink__lbl">{l.label}</span>
                <span className="alink__arr">↗</span>
              </a>
            ))}
          </div>
        </div>
      </div>

      <div className="artist-card__footer">
        <div className="bars">
          {Array.from({ length: 28 }).map((_, i) => (
            <span key={i} style={{ animationDelay: `${(i % 7) * 80}ms` }} />
          ))}
        </div>
        <div className="artist-card__footer-txt">TRANSMISSION STABLE · PAYLOAD: VOCAL</div>
      </div>
    </div>
  );
}

// ---------- Player ----------
function Player({
  track, isPlaying, progress, duration, onToggle, onSeek, onPrev, onNext,
  volume, onVolume, trackIndex, trackCount,
}) {
  const pct = duration ? (progress / duration) * 100 : 0;

  return (
    <div className="player">
      <div className="player__top">
        <div className="player__cover">
          <img src="assets/epidemic-master.png" alt="epideM:Ic cover" />
          <div className="player__cover-pulse" />
        </div>

        <div className="player__info">
          <div className="player__crumb">
            <span className="crumb">TRK {(trackIndex + 1).toString().padStart(2, "0")}/{trackCount.toString().padStart(2, "0")}</span>
            <span className="crumb crumb--live">
              <span className="dot dot--green" /> {isPlaying ? "STREAMING" : "STANDBY"}
            </span>
          </div>
          <div className="player__title">{track.title}</div>
          <div className="player__artists">
            {track.artistIds.map((id, i) => (
              <span key={id}>
                {i > 0 && <span className="player__artists-sep">×</span>}
                <span className="player__artist-chip">{ARTISTS[id].name}</span>
              </span>
            ))}
          </div>
        </div>

        <div className="player__vu">
          <VU playing={isPlaying} />
        </div>
      </div>

      <Waveform
        track={track}
        progress={progress}
        duration={duration}
        onSeek={onSeek}
      />

      <div className="player__timecode">
        <span>{fmt(progress)}</span>
        <div className="tc-mid">
          {track.verses.map((v) => {
            const active = progress >= v.start && progress < v.end;
            return (
              <span key={v.id} className={`tc-chip ${active ? "is-active" : ""}`}>
                <span className="tc-chip__dot" />
                {v.label}
              </span>
            );
          })}
        </div>
        <span>-{fmt(Math.max(0, duration - progress))}</span>
      </div>

      <div className="player__controls">
        <div className="player__ctrl-left">
          <button className="iconbtn" onClick={onPrev} aria-label="Previous">⏮</button>
          <button className="iconbtn iconbtn--primary" onClick={onToggle} aria-label="Play/Pause">
            {isPlaying ? "❚❚" : "▶"}
          </button>
          <button className="iconbtn" onClick={onNext} aria-label="Next">⏭</button>
          <div className="player__progress-num">{pct.toFixed(1).padStart(4, "0")}%</div>
        </div>

        <div className="player__ctrl-right">
          <div className="vol">
            <span className="vol__ico">♫</span>
            <input
              type="range" min="0" max="1" step="0.01"
              value={volume} onChange={(e) => onVolume(parseFloat(e.target.value))}
            />
            <span className="vol__num">{Math.round(volume * 100).toString().padStart(2, "0")}</span>
          </div>
          <div className="quality">
            <span className="quality__dot" />
            <span>LOSSLESS · 24/96</span>
          </div>
        </div>
      </div>
    </div>
  );
}

// ---------- Waveform (procedural, seekable) ----------
function Waveform({ track, progress, duration, onSeek }) {
  const ref = useRef(null);
  const bars = useMemo(() => {
    // Deterministic per-track shape
    const seed = track.id.split("").reduce((a, c) => a + c.charCodeAt(0), 0);
    const rnd = (i) => {
      const x = Math.sin((seed + i) * 12.9898) * 43758.5453;
      return x - Math.floor(x);
    };
    const N = 120;
    const arr = [];
    for (let i = 0; i < N; i++) {
      const t = i / N;
      // Envelope: builds, choruses, drops
      const env =
        0.35 +
        0.45 * Math.sin(t * Math.PI) +
        0.18 * Math.sin(t * Math.PI * 6 + rnd(i) * 2) +
        0.10 * rnd(i * 3);
      arr.push(Math.max(0.08, Math.min(1, env)));
    }
    return arr;
  }, [track.id]);

  const pct = duration ? progress / duration : 0;

  const handleClick = (e) => {
    if (!ref.current || !duration) return;
    const r = ref.current.getBoundingClientRect();
    const x = (e.clientX - r.left) / r.width;
    onSeek(Math.max(0, Math.min(1, x)) * duration);
  };

  return (
    <div className="waveform" ref={ref} onClick={handleClick}>
      <div className="waveform__verse-markers">
        {track.verses.map((v) => {
          const left = (v.start / duration) * 100;
          const w = ((v.end - v.start) / duration) * 100;
          return (
            <div
              key={v.id}
              className="verse-marker"
              style={{ left: `${left}%`, width: `${w}%` }}
              data-label={v.label}
            >
              <span className="verse-marker__lbl">{v.label}</span>
            </div>
          );
        })}
      </div>
      <div className="waveform__bars">
        {bars.map((h, i) => {
          const filled = i / bars.length <= pct;
          return (
            <span
              key={i}
              className={`wb ${filled ? "is-filled" : ""}`}
              style={{ height: `${h * 100}%` }}
            />
          );
        })}
      </div>
      <div className="waveform__playhead" style={{ left: `${pct * 100}%` }}>
        <span className="ph-flag">{fmt(progress)}</span>
      </div>
    </div>
  );
}

// ---------- VU meter ----------
function VU({ playing }) {
  const [vals, setVals] = useState(Array.from({ length: 12 }, () => 0.2));
  useEffect(() => {
    if (!playing) {
      setVals((v) => v.map(() => 0.05));
      return;
    }
    const id = setInterval(() => {
      setVals((v) => v.map(() => 0.2 + Math.random() * 0.8));
    }, 90);
    return () => clearInterval(id);
  }, [playing]);
  return (
    <div className="vu">
      {vals.map((v, i) => (
        <div key={i} className="vu__col">
          <div className="vu__bar" style={{ height: `${v * 100}%` }} />
        </div>
      ))}
    </div>
  );
}

// ---------- Tracklist ----------
function Tracklist({ tracks, currentIdx, onPick, isPlaying, progress }) {
  return (
    <div className="tracklist">
      <div className="tracklist__hdr">
        <span>#</span>
        <span>TITLE / PERSONNEL</span>
        <span className="tl-hide">PAYLOAD</span>
        <span>RUN</span>
      </div>
      {tracks.map((t, i) => {
        const active = i === currentIdx;
        const trackPct = active && t.duration ? (progress / t.duration) * 100 : 0;
        return (
          <button
            key={t.id}
            className={`tl-row ${active ? "is-active" : ""}`}
            onClick={() => onPick(i)}
            title={t.title}
          >
            <span className="tl-num">
              {active ? (
                isPlaying ? (
                  <span className="tl-eq">
                    <span style={{ animationDelay: "0ms" }} />
                    <span style={{ animationDelay: "120ms" }} />
                    <span style={{ animationDelay: "240ms" }} />
                  </span>
                ) : (
                  <span className="tl-resume" aria-label="Resume">▶</span>
                )
              ) : (
                (i + 1).toString().padStart(2, "0")
              )}
            </span>
            <span className="tl-title">
              <span className="tl-title__main">{t.title}</span>
              <span className="tl-title__sub">
                {t.artistIds.map((id) => ARTISTS[id].name).join(" × ")}
                {t.explicit && <span className="expl">E</span>}
              </span>
              {active && (
                <span className="tl-prog">
                  <span className="tl-prog__fill" style={{ width: `${trackPct}%` }} />
                </span>
              )}
            </span>
            <span className="tl-hide tl-payload">{t.payload}</span>
            <span className="tl-dur">{fmt(t.duration)}</span>
          </button>
        );
      })}
    </div>
  );
}

// Export
Object.assign(window, {
  ArtistCard, Player, Tracklist, Waveform, VU, fmt,
});
