// Queue state store - event-driven view of Rust player queue
//
// This store listens for queue_changed events from the Rust backend
// and provides reactive state for the frontend. All business logic
// (shuffle order, next/previous calculations, etc.) is handled by Rust.
//
// TRACES: UR-005, UR-015 | DR-005, DR-020

import { writable, derived, get } from "svelte/store";
import { commands, events } from "$lib/api/bindings";
import type { MediaItem } from "$lib/api/types";
import { auth } from "$lib/stores/auth";

export type RepeatMode = "off" | "all" | "one";

interface QueueState {
  items: MediaItem[];
  currentIndex: number | null;
  shuffle: boolean;
  repeat: RepeatMode;
  hasNext: boolean;
  hasPrevious: boolean;
}

interface QueueChangedEvent {
  items: MediaItem[];
  currentIndex: number | null;
  shuffle: boolean;
  repeat: RepeatMode;
  hasNext: boolean;
  hasPrevious: boolean;
}

function createQueueStore() {
  const initialState: QueueState = {
    items: [],
    currentIndex: null,
    shuffle: false,
    repeat: "off",
    hasNext: false,
    hasPrevious: false,
  };

  const { subscribe, set } = writable<QueueState>(initialState);

  // Listen for queue changed events from Rust backend
  let unlisten: (() => void) | null = null;

  async function init() {
    // Initial sync from backend
    await syncFromRust();

    // Listen for queue changed events (generated tauri-specta event)
    unlisten = await events.playerStatusEvent.listen((event) => {
      if (event.payload.type === "queue_changed") {
        const queueEvent = event.payload;
        set({
          items: queueEvent.items as unknown as MediaItem[],
          currentIndex: queueEvent.current_index,
          shuffle: queueEvent.shuffle,
          repeat: queueEvent.repeat,
          hasNext: queueEvent.has_next,
          hasPrevious: queueEvent.has_previous,
        });
      }
    });
  }

  /**
   * Sync queue state from Rust backend (for initial load)
   */
  async function syncFromRust(): Promise<void> {
    try {
      const rustQueue = (await commands.playerGetQueue()) as unknown as QueueChangedEvent;
      console.log("[Queue] Synced from Rust - items:", rustQueue.items.length);
      set({
        items: rustQueue.items,
        currentIndex: rustQueue.currentIndex,
        shuffle: rustQueue.shuffle,
        repeat: rustQueue.repeat,
        hasNext: rustQueue.hasNext,
        hasPrevious: rustQueue.hasPrevious,
      });
    } catch (error) {
      console.error("[Queue] Failed to sync from Rust:", error);
    }
  }

  /**
   * Clean up event listener
   */
  function cleanup() {
    if (unlisten) {
      unlisten();
      unlisten = null;
    }
  }

  // Initialize on creation
  init();

  // All queue operations now invoke backend commands
  // Backend handles all business logic and emits events

  // TRACES: UR-005, UR-015 | DR-005
  async function next() {
    await commands.playerNext();
  }

  // TRACES: UR-005, UR-015 | DR-005
  async function previous() {
    await commands.playerPrevious();
  }

  // TRACES: UR-005, UR-015 | DR-005, DR-020
  async function skipTo(index: number) {
    await commands.playerSkipTo(index);
  }

  // TRACES: UR-005, UR-015 | DR-005
  async function toggleShuffle() {
    await commands.playerToggleShuffle();
  }

  // TRACES: UR-005, UR-015 | DR-005
  async function cycleRepeat() {
    await commands.playerCycleRepeat();
  }

  // TRACES: UR-015 | DR-020
  async function removeFromQueue(index: number) {
    await commands.playerRemoveFromQueue(index);
  }

  // TRACES: UR-015 | DR-020
  async function moveInQueue(fromIndex: number, toIndex: number) {
    await commands.playerMoveInQueue(fromIndex, toIndex);
  }

  // TRACES: UR-015 | DR-020
  async function addToQueue(items: MediaItem | MediaItem[], position: "next" | "end" = "end") {
    const toAdd = Array.isArray(items) ? items : [items];
    const trackIds = toAdd.map((item) => item.id);

    // Get repository handle from auth store
    const authState = get(auth);
    if (!authState.isAuthenticated) {
      throw new Error("User not authenticated");
    }
    const repositoryHandle = auth.getRepository().getHandle();

    // Use new Rust commands that accept IDs only
    if (trackIds.length === 1) {
      await commands.playerAddTrackById(repositoryHandle, {
        trackId: trackIds[0],
        position,
      });
    } else {
      await commands.playerAddTracksByIds(repositoryHandle, {
        trackIds,
        position,
      });
    }
  }

  async function clear() {
    set(initialState);
  }

  return {
    subscribe,
    next,
    previous,
    skipTo,
    toggleShuffle,
    cycleRepeat,
    addToQueue,
    removeFromQueue,
    moveInQueue,
    syncFromRust,
    cleanup,
    clear,
  };
}

export const queue = createQueueStore();

// Derived stores for convenience
export const queueItems = derived(queue, ($q) => $q.items);
export const currentQueueIndex = derived(queue, ($q) => $q.currentIndex);
export const currentQueueItem = derived(queue, ($q) =>
  $q.currentIndex !== null ? $q.items[$q.currentIndex] : null
);
export const isShuffle = derived(queue, ($q) => $q.shuffle);
export const repeatMode = derived(queue, ($q) => $q.repeat);
export const hasNext = derived(queue, ($q) => $q.hasNext);
export const hasPrevious = derived(queue, ($q) => $q.hasPrevious);
