/**
 * Tests for `shouldShowAudioMiniPlayer` visibility invariant.
 *
 * The mini player must NOT flicker out while advancing between tracks. The
 * backend can momentarily report an idle/stopped state mid-transition, so the
 * bar stays visible as long as a queue item still exists, and only hides once
 * playback has genuinely ended and the queue has been cleared.
 *
 * TRACES: UR-005 | DR-009
 */

import { describe, it, expect, beforeEach, vi } from "vitest";
import { writable } from "svelte/store";
import { get } from "svelte/store";
import type { MediaItem } from "$lib/api/types";

// Mock the dependency stores so we can drive remote mode and the current queue
// item independently of the real backend listeners.
const isRemoteMode = writable(false);
const selectedSession = writable<any>(null);
const currentQueueItem = writable<MediaItem | null>(null);

vi.mock("./playbackMode", () => ({ isRemoteMode }));
vi.mock("./sessions", () => ({ selectedSession }));
vi.mock("./queue", () => ({ currentQueueItem }));

// Imported after the mocks so player.ts picks up the mocked stores.
const { player, shouldShowAudioMiniPlayer } = await import("./player");

const audioItem = { id: "a1", type: "Audio" } as unknown as MediaItem;
const videoItem = { id: "v1", type: "Movie" } as unknown as MediaItem;

describe("shouldShowAudioMiniPlayer", () => {
  beforeEach(() => {
    isRemoteMode.set(false);
    selectedSession.set(null);
    currentQueueItem.set(null);
    player.setIdle();
  });

  it("shows while an audio track is playing", () => {
    player.setPlaying(audioItem, 0, 100);
    expect(get(shouldShowAudioMiniPlayer)).toBe(true);
  });

  it("stays visible through a transient idle blip while still queued", () => {
    // A track is queued (e.g. mid-transition the backend emits idle but the
    // next track is already in the queue).
    currentQueueItem.set(audioItem);
    player.setIdle();
    expect(get(shouldShowAudioMiniPlayer)).toBe(true);
  });

  it("stays visible through loading/seeking transitions", () => {
    currentQueueItem.set(audioItem);
    player.setLoading(audioItem);
    expect(get(shouldShowAudioMiniPlayer)).toBe(true);
    player.setSeeking(audioItem, 10);
    expect(get(shouldShowAudioMiniPlayer)).toBe(true);
  });

  it("hides once playback ends and the queue is cleared", () => {
    currentQueueItem.set(null);
    player.setIdle();
    expect(get(shouldShowAudioMiniPlayer)).toBe(false);
  });

  it("hides for video content even while playing", () => {
    player.setPlaying(videoItem, 0, 100);
    expect(get(shouldShowAudioMiniPlayer)).toBe(false);
  });

  it("hides for video content reported only via the queue item", () => {
    currentQueueItem.set(videoItem);
    player.setIdle();
    expect(get(shouldShowAudioMiniPlayer)).toBe(false);
  });

  it("hides a video queue item that has no Jellyfin `type` but mediaType 'video'", () => {
    // Regression: player_play_item (every Movie/Episode via VideoPlayer) pushes
    // a backend PlayerMediaItem onto the queue with item_type: None but
    // media_type: Video → serialized with no `type` and mediaType: "video".
    // Without the mediaType check this slipped past the Movie/Episode guard and
    // surfaced the last-played video in the audio mini player after leaving
    // /player.
    const videoQueueItem = { id: "v2", mediaType: "video" } as unknown as MediaItem;
    currentQueueItem.set(videoQueueItem);
    player.setIdle();
    expect(get(shouldShowAudioMiniPlayer)).toBe(false);
  });

  it("hides for a live TV channel", () => {
    const channelItem = { id: "c1", type: "TvChannel" } as unknown as MediaItem;
    player.setPlaying(channelItem, 0, 0);
    expect(get(shouldShowAudioMiniPlayer)).toBe(false);
  });

  it("shows in remote mode when the session has a now-playing item", () => {
    isRemoteMode.set(true);
    selectedSession.set({ nowPlayingItem: { id: "r1" } });
    expect(get(shouldShowAudioMiniPlayer)).toBe(true);
  });
});
