/* Garbashala — Music Room */

const MUSIC_COVER_BY_TRACK_ID = window.GARBASHALA_MUSIC_ARTWORK || {};

const MUSIC_FALLBACK_COVERS = [
  "/assets/steps/kanudo/kanudo-album-cover.jpg",
  "/assets/steps/ghee-na-diva/ghee-na-diva-cover.jpg",
  "/assets/steps/cept-mandli/pethal-purma-pavo-vagyo-cover.jpg",
  "/assets/steps/tran-taali/tetudo-cover.jpg",
];

const MusicIcon = ({ name, label }) => (
  <img
    className="music-icon"
    src={`https://unpkg.com/lucide-static@0.468.0/icons/${name}.svg`}
    alt={label || ""}
    aria-hidden={label ? undefined : "true"}
  />
);

const musicCoverFor = (track) => (
  MUSIC_COVER_BY_TRACK_ID[track.spotifyId]
  || MUSIC_FALLBACK_COVERS[(track.index - 1) % MUSIC_FALLBACK_COVERS.length]
);

const musicSeconds = (duration) => {
  const [minutes, seconds] = String(duration).split(":").map(Number);
  return Number.isFinite(minutes) && Number.isFinite(seconds) ? (minutes * 60) + seconds : 0;
};

const formatMusicTime = (seconds) => {
  if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
  const rounded = Math.floor(seconds);
  return `${Math.floor(rounded / 60)}:${String(rounded % 60).padStart(2, "0")}`;
};

const musicTitleAliases = {
  "lili lembadi re": "lili lemdi re",
  "nagar nandaji na lal": "naagar nandji na laal",
  "ma taro garbo": "maa taro garbo",
  "ghina diva pani ma bale": "ghina diva poni ma bale",
  "kumkum pagale madi padharo": "kum kum pagle madi padharo",
  "saibo re govaliyo": "saybo re govaliyo",
  "tari mass mithi madd mithi vaate": "tari madh mithi madh mithi vaate",
  "navlaakhaai lobadiyaliyu": "navalakhay lobadiyaliyu",
  "jode rejo raj": "jode rehjo raaj",
  "radha govaladi": "radha govalni",
  "ame kaka bapa ne poriya": "ame kaka bapana poriya",
  "jilan jilva gaya ta": "jilan jilva gya ta",
  "pethalpur ma pavo vagyo": "pethalpurma pavo vagyo",
  "eke lal darvaje": "eke lal darwaje",
  "vithal vithal vithala": "vitthal vitthal vitthala",
};

const musicTitleKey = (title) => {
  const normalized = title
    .toLocaleLowerCase()
    .normalize("NFKD")
    .replace(/\([^)]*\)/g, " ")
    .replace(/\b(from|feat|ft|version|remix|remastered|live)\b.*$/g, " ")
    .replace(/[^\p{L}\p{N}]+/gu, " ")
    .trim();
  return musicTitleAliases[normalized] || normalized;
};

const uniqueMusicTracks = (tracks) => {
  const seenTitles = new Set();
  return tracks.filter((track) => {
    const titleKey = musicTitleKey(track.title);
    if (seenTitles.has(titleKey)) return false;
    seenTitles.add(titleKey);
    return true;
  });
};

const Music = () => {
  const audioLibrary = window.GARBASHALA_MUSIC_AUDIO || {};
  const tracks = React.useMemo(() => uniqueMusicTracks([
    ...(window.GARBASHALA_MUSIC_TRACKS || []),
    ...(window.GARBASHALA_LOCAL_MUSIC_TRACKS || []),
  ].filter((track) => audioLibrary[track.spotifyId])), [audioLibrary]);
  const [query, setQuery] = React.useState("");
  const [currentIndex, setCurrentIndex] = React.useState(0);
  const [shuffle, setShuffle] = React.useState(false);
  const [playbackStatus, setPlaybackStatus] = React.useState("loading");
  const [elapsed, setElapsed] = React.useState(0);
  const [duration, setDuration] = React.useState(0);
  const [volume, setVolume] = React.useState(1);
  const [muted, setMuted] = React.useState(false);
  const audioRef = React.useRef(null);
  const current = tracks[currentIndex] || tracks[0];
  const currentAudio = current ? audioLibrary[current.spotifyId] : null;

  const audioSourceFor = (track) => audioLibrary[track.spotifyId]?.src;
  const audioDurationFor = (track) => audioLibrary[track.spotifyId]?.duration;

  const visibleTracks = React.useMemo(() => {
    const needle = query.trim().toLocaleLowerCase();
    return tracks.filter((track) => !needle || `${track.title} ${track.artist}`.toLocaleLowerCase().includes(needle));
  }, [query, tracks]);
  const trackIndexes = React.useMemo(
    () => new Map(tracks.map((track, index) => [track.spotifyId, index])),
    [tracks],
  );

  const totalSeconds = React.useMemo(() => tracks.reduce(
    (sum, track) => sum + (audioDurationFor(track) || musicSeconds(track.duration)),
    0,
  ), [audioLibrary, tracks]);
  const totalHours = Math.round(totalSeconds / 3600);
  const playableIndexes = React.useMemo(() => tracks.reduce((indexes, track, index) => {
    if (audioSourceFor(track)) indexes.push(index);
    return indexes;
  }, []), [audioLibrary, tracks]);

  const nextPlayableIndex = (direction = 1) => {
    if (!playableIndexes.length) return currentIndex;
    if (shuffle && direction > 0 && playableIndexes.length > 1) {
      const choices = playableIndexes.filter((index) => index !== currentIndex);
      return choices[Math.floor(Math.random() * choices.length)];
    }

    for (let offset = 1; offset <= tracks.length; offset += 1) {
      const index = (currentIndex + (direction * offset) + tracks.length) % tracks.length;
      if (audioSourceFor(tracks[index])) return index;
    }
    return currentIndex;
  };

  const loadTrack = (index, shouldAutoplay = false) => {
    if (!tracks[index]) return;
    setCurrentIndex(index);
    if (!shouldAutoplay) return;

    const audioUrl = audioSourceFor(tracks[index]);
    const audio = audioRef.current;
    if (!audio) return;
    if (!audioUrl) {
      audio.pause();
      audio.removeAttribute("src");
      audio.load();
      setPlaybackStatus("unavailable");
      return;
    }

    setPlaybackStatus("starting");
    audio.src = audioUrl;
    audio.currentTime = 0;
    setElapsed(0);
    setDuration(audioLibrary[tracks[index].spotifyId]?.duration || 0);
    audio.play()
      .then(() => setPlaybackStatus("playing"))
      .catch(() => setPlaybackStatus("blocked"));
  };

  const goNext = () => loadTrack(nextPlayableIndex(), true);

  const goPrevious = () => {
    loadTrack(nextPlayableIndex(-1), true);
  };

  const togglePlayback = () => {
    const audio = audioRef.current;
    if (!audio) return;
    if (audio.paused) {
      audio.play()
        .then(() => setPlaybackStatus("playing"))
        .catch(() => setPlaybackStatus("blocked"));
    } else {
      audio.pause();
    }
  };

  const seekTo = (event) => {
    const nextTime = Number(event.target.value);
    if (!audioRef.current || !Number.isFinite(nextTime)) return;
    audioRef.current.currentTime = nextTime;
    setElapsed(nextTime);
  };

  const changeVolume = (event) => {
    const nextVolume = Number(event.target.value);
    if (!audioRef.current || !Number.isFinite(nextVolume)) return;
    audioRef.current.volume = nextVolume;
    audioRef.current.muted = false;
    setMuted(false);
    setVolume(nextVolume);
  };

  const toggleMuted = () => {
    if (!audioRef.current) return;
    const nextMuted = !muted;
    audioRef.current.muted = nextMuted;
    setMuted(nextMuted);
  };

  React.useEffect(() => {
    document.title = "Music Room — Garba Shala";
    return () => { document.title = "Garba Shala — a free garba step library"; };
  }, []);

  React.useEffect(() => {
    const audio = audioRef.current;
    if (!audio || !currentAudio?.src || audio.getAttribute("src")) return;
    audio.src = currentAudio.src;
    audio.load();
    setDuration(currentAudio.duration || 0);
  }, []);

  React.useEffect(() => {
    const handleKeyDown = (event) => {
      const interactiveTarget = event.target?.closest?.("input, textarea, select, button, a, [contenteditable='true']");
      if (event.code !== "Space" || event.repeat || event.metaKey || event.ctrlKey || event.altKey || interactiveTarget) return;
      event.preventDefault();
      togglePlayback();
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, []);

  if (!current) return null;

  return (
    <div className="music-page paper-bg">
      <NavBar active="music" />

      <main className="music-content">
        <header className="music-heading-row">
          <div className="music-heading">
            <h1>music room</h1>
            <p>Find your rhythm, follow the beat, and practice without leaving the floor.</p>
          </div>
          <p className="music-count">{visibleTracks.length} songs · about {totalHours} hours</p>
        </header>

        <div className="music-room">
          <aside className="music-now" aria-live="polite">
            <div className="music-cover-wrap">
              <img className="music-cover" src={musicCoverFor(current)} alt={`${current.title} cover`} />
            </div>
            <div className="music-now-copy">
              <span className="music-playing-tag"><i /> now selected</span>
              <h2>{current.title}</h2>
              <p>{current.artist || "Unavailable on Spotify"}</p>
              <span className="music-now-meta">
                full track · {formatMusicTime(currentAudio.duration)}
              </span>
            </div>
          </aside>

          <section className="music-library" aria-labelledby="music-list-heading">
            <div className="music-tools">
              <label className="music-search">
                <MusicIcon name="search" />
                <input
                  type="search"
                  value={query}
                  onChange={(event) => setQuery(event.target.value)}
                  placeholder="Search songs or artists…"
                  aria-label="Search songs or artists"
                />
                {query && (
                  <button type="button" onClick={() => setQuery("")} aria-label="Clear search">
                    <MusicIcon name="x" />
                  </button>
                )}
              </label>
            </div>

            <div className="music-section-row">
              <h3 id="music-list-heading">songs for the floor</h3>
              {query ? <span>{visibleTracks.length} found</span> : null}
            </div>

            <div className="music-tracks">
              {visibleTracks.length ? visibleTracks.map((track) => {
                const trackIndex = trackIndexes.get(track.spotifyId);
                const selected = trackIndex === currentIndex;
                return (
                  <article className={`music-track${selected ? " is-current" : ""}`} key={track.spotifyId}>
                    <button
                      className="music-track-main"
                      type="button"
                      onClick={() => loadTrack(trackIndex, true)}
                      aria-label={`Select ${track.title} by ${track.artist}`}
                      aria-current={selected ? "true" : undefined}
                    >
                      <span className="music-track-number">
                        {selected ? <MusicIcon name="play" /> : String(trackIndex + 1).padStart(2, "0")}
                      </span>
                      <img src={musicCoverFor(track)} alt="" loading="lazy" />
                      <span className="music-track-copy">
                        <strong>{track.title}</strong>
                        <span>{track.artist || "Unavailable on Spotify"}</span>
                      </span>
                      <span className="music-track-duration">
                        {audioDurationFor(track) ? formatMusicTime(audioDurationFor(track)) : "—"}
                      </span>
                    </button>
                  </article>
                );
              }) : (
                <div className="music-empty">
                  <MusicIcon name="music-2" />
                  <strong>no songs found</strong>
                  <span>Try another title or artist.</span>
                </div>
              )}
            </div>
          </section>
        </div>
      </main>

      <section
        className="music-player"
        aria-label="Music player"
        data-playback-status={playbackStatus}
        data-shuffle={shuffle ? "on" : "off"}
      >
        <div className="music-player-track">
          <img src={musicCoverFor(current)} alt="" />
          <span>
            <strong>{current.title}</strong>
            <small>{current.artist || "Unavailable on Spotify"}</small>
          </span>
        </div>

        <div className="music-transport">
          <div className="music-transport-controls">
            <button
              className={shuffle ? "is-active" : ""}
              type="button"
              onClick={() => setShuffle((value) => !value)}
              aria-label={shuffle ? "Turn shuffle off" : "Turn shuffle on"}
              aria-pressed={shuffle}
            >
              <MusicIcon name="shuffle" />
            </button>
            <button type="button" onClick={goPrevious} aria-label="Previous song"><MusicIcon name="skip-back" /></button>
            <button className="music-play-toggle" type="button" onClick={togglePlayback} aria-label={playbackStatus === "playing" ? "Pause" : "Play"}>
              <MusicIcon name={playbackStatus === "playing" ? "pause" : "play"} />
            </button>
            <button type="button" onClick={goNext} aria-label="Next song"><MusicIcon name="skip-forward" /></button>
          </div>
          <div className="music-progress-row">
            <time>{formatMusicTime(elapsed)}</time>
            <input
              className="music-progress"
              type="range"
              min="0"
              max={duration || 0}
              step="0.1"
              value={Math.min(elapsed, duration || 0)}
              onChange={seekTo}
              aria-label="Seek through song"
              style={{ "--music-progress": `${duration ? (elapsed / duration) * 100 : 0}%` }}
            />
            <time>{formatMusicTime(duration)}</time>
          </div>
          <audio
            ref={audioRef}
            preload="metadata"
            aria-label={`${current.title} audio`}
            onPlay={() => setPlaybackStatus("playing")}
            onPause={() => setPlaybackStatus("paused")}
            onLoadedMetadata={(event) => setDuration(event.currentTarget.duration)}
            onTimeUpdate={(event) => setElapsed(event.currentTarget.currentTime)}
            onEnded={goNext}
            onError={() => setPlaybackStatus("unavailable")}
          />
        </div>

        <div className="music-player-actions">
          <button type="button" onClick={toggleMuted} aria-label={muted ? "Unmute" : "Mute"}>
            <MusicIcon name={muted || volume === 0 ? "volume-x" : "volume-2"} />
          </button>
          <input
            className="music-volume"
            type="range"
            min="0"
            max="1"
            step="0.05"
            value={muted ? 0 : volume}
            onChange={changeVolume}
            aria-label="Volume"
          />
          {!current.spotifyId.startsWith("local-") ? (
            <a className="music-open-spotify" href={`https://open.spotify.com/track/${current.spotifyId}`} target="_blank" rel="noopener noreferrer">
              <MusicIcon name="external-link" /> <span>Spotify</span>
            </a>
          ) : null}
        </div>
      </section>
    </div>
  );
};

window.Music = Music;
