/**
 * LMS multi-room sync ("fuse zones") store.
 *
 * The JellyLMS plugin registers each LMS player as a Jellyfin session whose
 * device id is `lms-{MacAddress}`. We use that prefix both to detect which cast
 * targets are fuseable LMS zones and to recover the MAC the SyncGroups API needs.
 *
 * Fusing model (per product decision): the currently-controlled zone is the sync
 * master; other selected zones join it. Toggling an already-grouped zone off
 * decouples just that zone; toggling the master off dissolves the group.
 *
 * TRACES: UR-010 | JA-021, JA-025 | DR-037
 */

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

const LMS_DEVICE_PREFIX = "lms-";

/** Is this cast target an LMS zone (and therefore fuseable)? */
export function isLmsSession(session: Session | null | undefined): boolean {
  return !!session?.deviceId?.startsWith(LMS_DEVICE_PREFIX);
}

/** Recover the LMS player MAC from a session, or null if it isn't an LMS zone. */
export function macForSession(session: Session | null | undefined): string | null {
  const deviceId = session?.deviceId;
  if (!deviceId?.startsWith(LMS_DEVICE_PREFIX)) return null;
  return deviceId.slice(LMS_DEVICE_PREFIX.length);
}

interface LmsSyncState {
  groups: LmsSyncGroup[];
  isBusy: boolean;
  error: string | null;
}

function createLmsSyncStore() {
  const { subscribe, update, set } = writable<LmsSyncState>({
    groups: [],
    isBusy: false,
    error: null,
  });

  /** Refresh the list of current sync groups from the server. */
  async function refresh(): Promise<void> {
    try {
      const groups = await commands.lmsGetSyncGroups();
      update((s) => ({ ...s, groups, error: null }));
    } catch (error) {
      // The plugin may not be installed; treat as "no groups" rather than fatal.
      console.warn("[LmsSync] Failed to load sync groups:", error);
      update((s) => ({ ...s, groups: [] }));
    }
  }

  /** All MACs that are part of any sync group (master or slave). */
  function groupedMacs(): Set<string> {
    const macs = new Set<string>();
    for (const g of get({ subscribe }).groups) {
      macs.add(g.masterMac);
      for (const slave of g.slaveMacs ?? []) macs.add(slave);
    }
    return macs;
  }

  /**
   * Add an LMS zone to the master's sync group (fuse it in).
   * Preserves any zones already grouped with the master.
   */
  async function fuseZone(masterMac: string, zoneMac: string): Promise<void> {
    if (masterMac === zoneMac) return;
    update((s) => ({ ...s, isBusy: true, error: null }));
    try {
      const existing = get({ subscribe }).groups.find((g) => g.masterMac === masterMac);
      const slaves = new Set(existing?.slaveMacs ?? []);
      slaves.add(zoneMac);
      await commands.lmsCreateSyncGroup(masterMac, [...slaves]);
      await refresh();
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fuse zone";
      update((s) => ({ ...s, error: message }));
      throw error;
    } finally {
      update((s) => ({ ...s, isBusy: false }));
    }
  }

  /**
   * Remove a single zone from its group. If the zone is a group's master, the
   * whole group is dissolved (a group can't outlive its master).
   */
  async function decoupleZone(zoneMac: string): Promise<void> {
    update((s) => ({ ...s, isBusy: true, error: null }));
    try {
      const asMaster = get({ subscribe }).groups.find((g) => g.masterMac === zoneMac);
      if (asMaster) {
        await commands.lmsDissolveSyncGroup(zoneMac);
      } else {
        await commands.lmsUnsyncPlayer(zoneMac);
      }
      await refresh();
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to decouple zone";
      update((s) => ({ ...s, error: message }));
      throw error;
    } finally {
      update((s) => ({ ...s, isBusy: false }));
    }
  }

  function clearError(): void {
    update((s) => ({ ...s, error: null }));
  }

  function reset(): void {
    set({ groups: [], isBusy: false, error: null });
  }

  return {
    subscribe,
    refresh,
    groupedMacs,
    fuseZone,
    decoupleZone,
    clearError,
    reset,
  };
}

export const lmsSync = createLmsSyncStore();
