import { join } from '@tauri-apps/api/path';
import { downloadZip } from '@/lib/api/downloadZip';
import { getSimilarSongs2, fetchSimilarTracksRouted, getTopSongs } from '@/lib/api/subsonicArtists';
import { filterSongsForLuckyMixRatings, getMixMinRatingsConfigFromAuth } from '@/features/playback/utils/mixRatingFilter';
import { buildDownloadUrl } from '@/lib/api/subsonicStreamUrl';
import { useAuthStore } from '@/store/authStore';
import { usePlayerStore } from '@/features/playback/store/playerStore';
import type { Track } from '@/lib/media/trackTypes';
import { resolveQueueTrack } from '@/features/playback/store/queueTrackView';
import { useZipDownloadStore } from '@/features/offline';
import { useDownloadModalStore } from '@/features/offline';
import type { EntityShareKind } from '@/lib/share/shareLink';
import { copyEntityShareLink } from '@/lib/share/copyEntityShareLink';
import { sanitizeFilename, shuffleArray } from '@/features/contextMenu/utils/contextMenuHelpers';
import { songToTrack } from '@/lib/media/songToTrack';
import { showToast } from '@/lib/dom/toast';

export async function copyShareLink(
  kind: EntityShareKind,
  id: string,
  t: (key: string) => string,
) {
  const ok = await copyEntityShareLink(kind, id);
  if (ok) showToast(t('contextMenu.shareCopied'));
  else showToast(t('contextMenu.shareCopyFailed'), 4000, 'error');
}

export async function startRadio(
  artistId: string,
  artistName: string,
  playTrack: (track: Track, queue: Track[]) => void,
  seedTrack?: Track,
) {
  if (seedTrack) {
    const state = usePlayerStore.getState();
    if (state.currentTrack?.id === seedTrack.id) {
      if (!state.isPlaying) state.resume();
    } else {
      playTrack(seedTrack, [seedTrack]);
    }
    try {
      const [similar, top] = await Promise.all([getSimilarSongs2(artistId), getTopSongs(artistName)]);
      const similarTracks = shuffleArray(
        similar.map(songToTrack).filter(t => t.id !== seedTrack.id).map(t => ({ ...t, radioAdded: true as const })),
      );
      const radioTracks = similarTracks.length > 0
        ? similarTracks
        : shuffleArray(
            top.map(songToTrack).filter(t => t.id !== seedTrack.id).map(t => ({ ...t, radioAdded: true as const })),
          );
      if (radioTracks.length > 0) usePlayerStore.getState().enqueueRadio(radioTracks, artistId);
    } catch (e) {
      console.error('Failed to load radio queue', e);
    }
    return;
  }

  // Artist radio without seed
  const similarPromise = getSimilarSongs2(artistId).catch(() => [] as Awaited<ReturnType<typeof getSimilarSongs2>>);
  try {
    const top = await getTopSongs(artistName);
    const topTracks = shuffleArray(
      top.map(t => ({ ...songToTrack(t), radioAdded: true as const })),
    );
    if (topTracks.length === 0) {
      const similar = await similarPromise;
      const fallback = shuffleArray(
        similar.map(t => ({ ...songToTrack(t), radioAdded: true as const })),
      );
      if (fallback.length === 0) return;
      const state = usePlayerStore.getState();
      if (state.currentTrack) {
        state.enqueueRadio(fallback, artistId);
      } else {
        state.setRadioArtistId(artistId);
        playTrack(fallback[0], fallback);
      }
      return;
    }
    const state = usePlayerStore.getState();
    if (state.currentTrack) {
      state.enqueueRadio([topTracks[0]], artistId);
    } else {
      state.setRadioArtistId(artistId);
      playTrack(topTracks[0], [topTracks[0]]);
    }
    similarPromise.then(similar => {
      const similarTracks = shuffleArray(
        similar
          .map(t => ({ ...songToTrack(t), radioAdded: true as const }))
          .filter(t => t.id !== topTracks[0].id),
      );
      if (similarTracks.length === 0) return;
      const { queueItems, queueIndex } = usePlayerStore.getState();
      // Thin-state: resolve the upcoming radio refs (cache-warm window) back to
      // Tracks so they merge with the new similars in enqueueRadio.
      const pendingRadio = queueItems
        .slice(queueIndex + 1)
        .filter(r => r.radioAdded)
        .map(r => resolveQueueTrack(r));
      usePlayerStore.getState().enqueueRadio([...pendingRadio, ...similarTracks], artistId);
    });
  } catch (e) {
    console.error('Failed to start radio', e);
  }
}

export async function startInstantMix(
  song: Track,
  t: (key: string) => string,
) {
  usePlayerStore.getState().reseedQueueForInstantMix(song);
  const serverId = useAuthStore.getState().activeServerId;
  try {
    const similar = await fetchSimilarTracksRouted(song.id, 50);
    if (serverId) useAuthStore.getState().setAudiomuseNavidromeIssue(serverId, false);
    const mixCfg = getMixMinRatingsConfigFromAuth();
    const ratedFiltered = await filterSongsForLuckyMixRatings(
      similar.filter(s => s.id !== song.id),
      mixCfg,
    );
    const shuffled = shuffleArray(
      ratedFiltered.map(s => ({ ...songToTrack(s), radioAdded: true as const })),
    );
    if (shuffled.length > 0) {
      const aid = song.artistId?.trim() || undefined;
      usePlayerStore.getState().enqueueRadio(shuffled, aid);
    }
  } catch (e) {
    console.error('Instant mix failed', e);
    if (serverId) useAuthStore.getState().setAudiomuseNavidromeIssue(serverId, true);
    showToast(t('contextMenu.instantMixFailed'), 5000, 'error');
  }
}

export async function downloadAlbum(albumName: string, albumId: string) {
  const auth = useAuthStore.getState();
  const requestDownloadFolder = useDownloadModalStore.getState().requestFolder;
  const folder = auth.downloadFolder || await requestDownloadFolder();
  if (!folder) return;

  const filename = `${sanitizeFilename(albumName)}.zip`;
  const destPath = await join(folder, filename);
  const url = buildDownloadUrl(albumId);
  const id = crypto.randomUUID();

  const { start, complete, fail } = useZipDownloadStore.getState();
  start(id, filename);
  try {
    await downloadZip({ id, url, destPath });
    complete(id);
  } catch (e) {
    fail(id);
    console.error('ZIP download failed:', e);
  }
}
