"use client";

import { useEffect, useState } from "react";
import { Modal } from "./modal";
import { CoverArt } from "./cover-art";
import { toast } from "./toast";
import type { ArtistPlays } from "@/lib/lastfm";

type Rel = {
  rgMbid: string;
  album: string;
  primaryType: string | null;
  secondaryTypes: string[];
  firstReleaseDate: string | null;
  monitored: boolean;
  have: boolean;
};
type Preview = { artistName: string; followed: boolean; releases: Rel[] };

type ReleaseGroupMatch = {
  rgMbid: string;
  title: string;
  primaryType: string | null;
  secondaryTypes: string[];
  firstReleaseDate: string | null;
  artistMbid: string;
  artistName: string;
};

/** Lightweight artist preview in a modal: follow + a cover-art grid of their releases with
 *  per-album Want. Reuses the discovery preview endpoint. The full preview page stays for
 *  deep links (linked here as "Full page"). When `lastfmName` is set (the /lastfm page only)
 *  it also shows the caller's most-played songs/albums for this artist, fetched independently
 *  of the preview above so it never blocks the existing grid. */
export function ArtistModal({
  open,
  onClose,
  mbid,
  initialName,
  lastfmName,
}: {
  open: boolean;
  onClose: () => void;
  mbid: string;
  initialName: string;
  lastfmName?: string;
}) {
  const [data, setData] = useState<Preview | "loading" | "error">("loading");
  const [followed, setFollowed] = useState(false);
  const [wanted, setWanted] = useState<Set<string>>(new Set());
  const [plays, setPlays] = useState<ArtistPlays | "loading" | "error" | null>(null);
  const [wantedAlbums, setWantedAlbums] = useState<Set<string>>(new Set());

  useEffect(() => {
    if (!open) return;
    setData("loading");
    setWanted(new Set());
    let cancelled = false;
    const qs = new URLSearchParams();
    if (initialName) qs.set("name", initialName);
    fetch(`/api/discover/preview/${mbid}?${qs.toString()}`)
      .then((r) => (r.ok ? r.json() : Promise.reject()))
      .then((d: Preview) => {
        if (cancelled) return;
        setData(d);
        setFollowed(d.followed);
      })
      .catch(() => !cancelled && setData("error"));
    return () => {
      cancelled = true;
    };
  }, [open, mbid, initialName]);

  useEffect(() => {
    if (!open || !lastfmName) {
      setPlays(null);
      setWantedAlbums(new Set());
      return;
    }
    setPlays("loading");
    setWantedAlbums(new Set());
    let cancelled = false;
    fetch(`/api/lastfm/artist-plays?artist=${encodeURIComponent(lastfmName)}`)
      .then((r) => (r.ok ? r.json() : Promise.reject()))
      .then((d: ArtistPlays) => {
        if (!cancelled) setPlays(d);
      })
      .catch(() => !cancelled && setPlays("error"));
    return () => {
      cancelled = true;
    };
  }, [open, lastfmName]);

  const name = typeof data === "object" ? data.artistName || initialName : initialName;

  async function follow() {
    const res = await fetch("/api/artists", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ mbid, name }),
    });
    if (res.ok || res.status === 409) {
      setFollowed(true);
      toast(`Following ${name}`);
    } else {
      toast(`Couldn't follow ${name}`);
    }
  }

  async function want(r: Rel) {
    const res = await fetch("/api/discover/want", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        rgMbid: r.rgMbid,
        artistMbid: mbid,
        artistName: name,
        album: r.album,
        primaryType: r.primaryType,
        secondaryTypes: r.secondaryTypes,
        firstReleaseDate: r.firstReleaseDate,
      }),
    });
    if (res.ok) {
      setWanted((s) => new Set(s).add(r.rgMbid));
      toast(`Added ${r.album}`);
    } else {
      toast(`Couldn't add ${r.album}`);
    }
  }

  async function wantAlbum(albumName: string) {
    const res = await fetch(
      `/api/mb/release-group?artist=${encodeURIComponent(lastfmName!)}&album=${encodeURIComponent(albumName)}`,
    );
    if (!res.ok) {
      toast(`No MusicBrainz match for ${albumName}`);
      return;
    }
    const m: ReleaseGroupMatch = await res.json();
    const wantRes = await fetch("/api/discover/want", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        rgMbid: m.rgMbid,
        artistMbid: mbid,
        artistName: name,
        album: m.title,
        primaryType: m.primaryType,
        secondaryTypes: m.secondaryTypes,
        firstReleaseDate: m.firstReleaseDate,
      }),
    });
    if (wantRes.ok) {
      setWantedAlbums((s) => new Set(s).add(albumName));
      toast(`Added ${m.title}`);
    }
  }

  return (
    <Modal open={open} onClose={onClose} title="Artist" wide>
      <div className="artist-modal-head">
        <h2 className="album-modal-title">{name || "Artist"}</h2>
        <div className="actions artist-modal-actions">
          {followed ? <span className="following">Following</span> : (
            <button className="btn accent sm" onClick={follow}>
              Follow
            </button>
          )}
          <a href={`/discover/artist/${mbid}?name=${encodeURIComponent(name)}`}>Full page ↗</a>
        </div>
      </div>

      {lastfmName ? (
        <div className="am-lastfm">
          {plays === "loading" ? <p className="muted-note">Loading your plays…</p> : null}
          {plays === "error" ? <p className="muted-note">Couldn’t load your Last.fm plays.</p> : null}
          {plays && typeof plays === "object" ? (
            plays.topTracks.length === 0 && plays.topAlbums.length === 0 ? (
              <p className="muted-note">No play data.</p>
            ) : (
              <>
                {plays.topTracks.length > 0 ? (
                  <>
                    <h3 className="subhead">Most played songs</h3>
                    <ol className="tracks">
                      {plays.topTracks.map((t, i) => (
                        <li key={t.name}>
                          <span className="tnum">{i + 1}</span>
                          <span className="tname">{t.name}</span>
                          <span>{t.plays} plays</span>
                        </li>
                      ))}
                    </ol>
                  </>
                ) : null}
                {plays.topAlbums.length > 0 ? (
                  <>
                    <h3 className="subhead">Most played albums</h3>
                    <ul className="list">
                      {plays.topAlbums.map((album) => {
                        const rel =
                          typeof data === "object"
                            ? data.releases.find(
                                (r) => r.album.toLowerCase().trim() === album.name.toLowerCase().trim(),
                              )
                            : undefined;
                        const owned = rel?.have ?? false;
                        const working = (rel?.monitored ?? false) || wantedAlbums.has(album.name);
                        return (
                          <li key={album.name} className="list-row">
                            <div className="main">
                              <div className="rtitle">{album.name}</div>
                              <div className="rmeta">
                                <span>{album.plays} plays</span>
                              </div>
                            </div>
                            <div className="actions">
                              {owned ? (
                                <span className="chip done">In library</span>
                              ) : working ? (
                                <span className="chip working">Wanted</span>
                              ) : (
                                <button className="btn sm" onClick={() => wantAlbum(album.name)}>
                                  Want
                                </button>
                              )}
                            </div>
                          </li>
                        );
                      })}
                    </ul>
                  </>
                ) : null}
                {plays.sampled ? (
                  <p className="muted-note">Top of your most recent ~1000 scrobbles.</p>
                ) : null}
              </>
            )
          ) : null}
        </div>
      ) : null}

      {data === "loading" ? <p className="muted-note">Loading…</p> : null}
      {data === "error" ? <p className="muted-note">Couldn’t load this artist.</p> : null}
      {typeof data === "object" ? (
        data.releases.length === 0 ? (
          <p className="muted-note">No releases found.</p>
        ) : (
          <div className="artist-modal-grid">
            {data.releases.slice(0, 18).map((r) => {
              const owned = r.have;
              const monitored = r.monitored || wanted.has(r.rgMbid);
              return (
                <div key={r.rgMbid} className="am-rel">
                  <CoverArt rgMbid={r.rgMbid} alt={r.album} />
                  <div className="ac-title">{r.album}</div>
                  <div className="ac-meta">
                    {r.primaryType}
                    {r.firstReleaseDate ? ` · ${r.firstReleaseDate.slice(0, 4)}` : ""}
                  </div>
                  <div className="am-rel-action">
                    {owned ? (
                      <span className="chip done">In library</span>
                    ) : monitored ? (
                      <span className="chip working">Wanted</span>
                    ) : (
                      <button className="btn sm" onClick={() => want(r)}>
                        Want
                      </button>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        )
      ) : null}
    </Modal>
  );
}
