// Remote sessions store for controlling playback on other Jellyfin clients
// TRACES: UR-010 | DR-037

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

interface SessionsState {
  sessions: Session[];
  selectedSessionId: string | null;
  isLoading: boolean;
  error: string | null;
  lastUpdated: Date | null;
}

function createSessionsStore() {
  const initialState: SessionsState = {
    sessions: [],
    selectedSessionId: null,
    isLoading: false,
    error: null,
    lastUpdated: null,
  };

  const { subscribe, update } = writable<SessionsState>(initialState);

  // Listen for session updates from Rust backend (generated tauri-specta event)
  events.playerStatusEvent.listen((event) => {
    if (event.payload.type === "sessions_updated") {
      const sessions = event.payload.sessions as unknown as Session[];
      console.log(`[Sessions] Received ${sessions.length} sessions from backend`);
      sessions.forEach((s, i) => {
        console.log(`[Sessions] Session ${i}: id=${s.id}, device=${s.deviceName}, supportsRemoteControl=${s.supportsRemoteControl}`);
      });
      update((s) => ({
        ...s,
        sessions,
        lastUpdated: new Date(),
        error: null,
      }));
    }
  });

  /**
   * Manually fetch sessions from backend (for refresh button)
   */
  async function refresh(): Promise<void> {
    try {
      update((s) => ({ ...s, isLoading: true, error: null }));

      const sessions = await commands.sessionsPollNow();

      console.log(`[Sessions] Manual refresh returned ${sessions.length} sessions`);
      sessions.forEach((s, i) => {
        console.log(`[Sessions] Session ${i}: id=${s.id}, device=${s.deviceName}, supportsRemoteControl=${s.supportsRemoteControl}`);
      });

      update((s) => ({
        ...s,
        sessions,
        isLoading: false,
        lastUpdated: new Date(),
        error: null,
      }));
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch sessions";
      update((s) => ({
        ...s,
        isLoading: false,
        error: message,
      }));
      console.error("Failed to fetch sessions:", error);
    }
  }


  /**
   * Select a session for control
   */
  function selectSession(sessionId: string | null): void {
    update((s) => ({ ...s, selectedSessionId: sessionId }));
  }

  /**
   * Send play/pause toggle command
   */
  async function sendPlayPause(sessionId: string | null | undefined): Promise<void> {
    try {
      await commands.remoteSendCommand(sessionId ?? "", "PlayPause");
      // Refresh after command to get updated state
      await refresh();
    } catch (error) {
      console.error("Failed to send play/pause command:", error);
      throw error;
    }
  }

  /**
   * Send stop command
   */
  async function sendStop(sessionId: string | null | undefined): Promise<void> {
    try {
      await commands.remoteSendCommand(sessionId ?? "", "Stop");
      await refresh();
    } catch (error) {
      console.error("Failed to send stop command:", error);
      throw error;
    }
  }

  /**
   * Send next track command
   */
  async function sendNext(sessionId: string | null | undefined): Promise<void> {
    try {
      await commands.remoteSendCommand(sessionId ?? "", "NextTrack");
      await refresh();
    } catch (error) {
      console.error("Failed to send next track command:", error);
      throw error;
    }
  }

  /**
   * Send previous track command
   */
  async function sendPrevious(sessionId: string | null | undefined): Promise<void> {
    try {
      await commands.remoteSendCommand(sessionId ?? "", "PreviousTrack");
      await refresh();
    } catch (error) {
      console.error("Failed to send previous track command:", error);
      throw error;
    }
  }

  /**
   * Seek to position (in ticks)
   */
  async function sendSeek(sessionId: string | null | undefined, positionTicks: number): Promise<void> {
    try {
      await commands.remoteSessionSeek(sessionId ?? "", positionTicks);
      // Don't refresh immediately for seek to avoid UI lag
    } catch (error) {
      console.error("Failed to send seek command:", error);
      throw error;
    }
  }

  /**
   * Set volume (0-100)
   */
  async function sendVolume(sessionId: string | null | undefined, volume: number): Promise<void> {
    try {
      await commands.remoteSessionSetVolume(sessionId ?? "", volume);
      // Don't refresh immediately for volume to avoid UI lag
    } catch (error) {
      console.error("Failed to send volume command:", error);
      throw error;
    }
  }

  /**
   * Toggle mute
   */
  async function sendToggleMute(sessionId: string | null | undefined): Promise<void> {
    try {
      await commands.remoteSendCommand(sessionId ?? "", "ToggleMute");
      await refresh();
    } catch (error) {
      console.error("Failed to toggle mute:", error);
      throw error;
    }
  }

  /**
   * Play item(s) on remote session
   */
  async function playOnSession(
    sessionId: string | null | undefined,
    itemIds: string[],
    startIndex = 0
  ): Promise<void> {
    console.log("[SESSIONS] ========== playOnSession called ==========");
    console.log("[SESSIONS] sessionId:", sessionId);
    console.log("[SESSIONS] itemIds array:", itemIds);
    console.log("[SESSIONS] itemIds.length:", itemIds.length);
    console.log("[SESSIONS] itemIds JSON:", JSON.stringify(itemIds));
    console.log("[SESSIONS] startIndex:", startIndex);
    console.log("[SESSIONS] About to call commands.remotePlayOnSession");
    try {
      // Use Rust player's Jellyfin client for remote playback
      const result = await commands.remotePlayOnSession(sessionId ?? "", itemIds, startIndex);
      console.log("[SESSIONS] invoke succeeded, result:", result);
      await refresh();
    } catch (error) {
      console.error("[SESSIONS] Failed to play on session:", error);
      throw error;
    }
  }

  return {
    subscribe,
    refresh,
    selectSession,
    sendPlayPause,
    sendStop,
    sendNext,
    sendPrevious,
    sendSeek,
    sendVolume,
    sendToggleMute,
    playOnSession,
  };
}

export const sessions = createSessionsStore();

// Derived stores

/**
 * Sessions that are currently playing media
 */
export const activeSessions = derived(
  sessions,
  ($sessions) => $sessions.sessions.filter((s) => s.nowPlayingItem !== null)
);

/**
 * Currently selected session
 */
export const selectedSession = derived(
  sessions,
  ($sessions) =>
    $sessions.sessions.find((s) => s.id === $sessions.selectedSessionId) ?? null
);

/**
 * Controllable sessions (support remote control)
 */
export const controllableSessions = derived(
  sessions,
  ($sessions) => {
    const controllable = $sessions.sessions.filter((s) => s.supportsRemoteControl);
    console.log(`[Sessions] Filtering ${$sessions.sessions.length} total sessions, ${controllable.length} are controllable`);
    $sessions.sessions.forEach((s, i) => {
      const status = s.supportsRemoteControl ? "✓ CONTROLLABLE" : "✗ NOT CONTROLLABLE";
      console.log(`[Sessions]   ${status}: ${s.deviceName} (id=${s.id}, supportsRemoteControl=${s.supportsRemoteControl})`);
    });
    return controllable;
  }
);
