// Sync service - manages offline mutation queueing
//
// Simplified service that coordinates with the Rust backend.
// The Rust backend handles sync queue persistence and processing logic.
// This service provides a thin TypeScript API for queuing mutations.
//
// TRACES: UR-002, UR-017, UR-025 | DR-014

import { commands } from "$lib/api/bindings";
import { auth } from "$lib/stores/auth";

// The queue row shape comes from the generated bindings rather than a
// hand-written mirror — the mirror had already drifted (it predates `itemName`),
// and a drifted duplicate is how a field silently stops reaching the UI.
import type { SyncQueueItem } from "$lib/api/bindings";
export type { SyncQueueItem };

export type SyncOperation =
  | "mark_played"
  | "mark_unplayed"
  | "mark_favorite"
  | "unmark_favorite"
  | "update_progress"
  | "report_playback_start"
  | "report_playback_stopped"
  | "playlist_create"
  | "playlist_delete"
  | "playlist_rename"
  | "playlist_add_items"
  | "playlist_remove_items"
  | "playlist_reorder_item";

/**
 * Simplified sync service - handles offline mutation queueing
 *
 * The Rust backend maintains the sync queue in SQLite and is responsible
 * for processing queued items. This service provides a TypeScript API
 * for queueing and managing sync operations.
 */
class SyncService {
  /**
   * Start the sync service (lifecycle managed by Rust backend)
   */
  start(): void {
    console.log("[SyncService] Started");
  }

  /**
   * Stop the sync service (lifecycle managed by Rust backend)
   */
  stop(): void {
    console.log("[SyncService] Stopped");
  }

  /**
   * Queue a mutation for sync to server
   *
   * TRACES: UR-017, UR-025 | DR-014
   */
  async queueMutation(
    operation: SyncOperation,
    itemId: string,
    payload?: Record<string, unknown>
  ): Promise<number> {
    const userId = auth.getUserId();
    if (!userId) {
      throw new Error("Not authenticated");
    }

    const id = await commands.syncQueueMutation(
      userId,
      operation,
      itemId,
      payload ? JSON.stringify(payload) : null
    );

    console.log(`[SyncService] Queued ${operation} for item ${itemId}, id: ${id}`);
    return id;
  }

  // NOTE: `queueFavorite` is gone. Favourites are drained by Rust on the
  // `connectivity:reconnected` signal (DR-120) — the local write already sets
  // `pending_sync`, and a second queue here would push the same change twice.
  // See src-tauri/src/commands/favorites.rs.

  /**
   * Queue playback progress update
   * Also updates local state immediately
   */
  async queuePlaybackProgress(
    itemId: string,
    positionMs: number
  ): Promise<number> {
    // Update local state first
    await commands.storageUpdatePlaybackProgress(auth.getUserId() ?? "", itemId, positionMs);

    return this.queueMutation("update_progress", itemId, { positionMs });
  }

  /**
   * Queue mark as played
   * Also updates local state immediately
   */
  async queueMarkPlayed(itemId: string): Promise<number> {
    // storageSetWatched, not storageMarkPlayed: this is the watched *toggle*, so
    // it has to cover a season or series' episodes too. storageMarkPlayed stays
    // the single-item "this finished playing" path.
    await commands.storageSetWatched(auth.getUserId() ?? "", itemId, true);

    return this.queueMutation("mark_played", itemId);
  }

  /**
   * Queue mark as unwatched, the inverse of {@link queueMarkPlayed}.
   *
   * Same shape deliberately: the watched toggle has to work in both directions
   * offline, or un-marking would be the one half that needs a connection. The
   * drain pushes this as `clear_watch_history` — Jellyfin's mark-unplayed, which
   * is recursive over a season or series and also clears resume positions.
   *
   * TRACES: UR-073 | DR-158
   */
  async queueMarkUnplayed(itemId: string): Promise<number> {
    await commands.storageSetWatched(auth.getUserId() ?? "", itemId, false);

    return this.queueMutation("mark_unplayed", itemId);
  }

  /**
   * Get count of pending sync operations
   */
  async getPendingCount(): Promise<number> {
    const userId = auth.getUserId();
    if (!userId) {
      return 0;
    }

    return commands.syncGetPendingCount(userId);
  }

  /**
   * Get pending sync items (for debugging/monitoring)
   */
  async getPending(limit?: number): Promise<SyncQueueItem[]> {
    const userId = auth.getUserId();
    if (!userId) {
      return [];
    }

    return commands.syncGetPending(userId, limit ?? null);
  }

  /**
   * Clean up completed operations older than specified days
   */
  async cleanup(daysOld: number = 7): Promise<number> {
    const deleted = await commands.syncCleanupCompleted(daysOld);
    console.log(`[SyncService] Cleaned up ${deleted} old completed operations`);
    return deleted;
  }

  // ===== Playlist sync operations =====

  async queuePlaylistCreate(playlistId: string, name: string, itemIds: string[]): Promise<number> {
    return this.queueMutation("playlist_create", playlistId, { name, itemIds });
  }

  async queuePlaylistDelete(playlistId: string): Promise<number> {
    return this.queueMutation("playlist_delete", playlistId);
  }

  async queuePlaylistRename(playlistId: string, name: string): Promise<number> {
    return this.queueMutation("playlist_rename", playlistId, { name });
  }

  async queuePlaylistAddItems(playlistId: string, itemIds: string[]): Promise<number> {
    return this.queueMutation("playlist_add_items", playlistId, { itemIds });
  }

  async queuePlaylistRemoveItems(playlistId: string, entryIds: string[]): Promise<number> {
    return this.queueMutation("playlist_remove_items", playlistId, { entryIds });
  }

  async queuePlaylistReorderItem(playlistId: string, itemId: string, newIndex: number): Promise<number> {
    return this.queueMutation("playlist_reorder_item", playlistId, { itemId, newIndex });
  }

  /**
   * Clear all sync operations for the current user (called during logout)
   *
   * TRACES: UR-017 | DR-014
   */
  async clearUser(): Promise<void> {
    const userId = auth.getUserId();
    if (userId) {
      await commands.syncClearUser(userId);
      console.log("[SyncService] Cleared sync queue for user");
    }
  }
}

// Export singleton instance
export const syncService = new SyncService();
