// Persistent user preferences (volume, muted). Single localStorage entry,
// cross-tab sync via the native `storage` event. SSR-safe.
//
// Why not Zustand: two fields. Adding a dep + persist middleware is overkill
// for ~50 LOC of plain code that already matches the activePlayerBus pattern.

const STORAGE_KEY = 'djangocfg-audioplayer:prefs';
const DEFAULT_VOLUME = 1;
const DEFAULT_MUTED = false;

export type PlayerPreferences = {
  volume: number;
  muted: boolean;
};

type Listener = (prefs: PlayerPreferences) => void;

let cached: PlayerPreferences | null = null;
const listeners = new Set<Listener>();
let storageBound = false;

function clamp01(v: number): number {
  if (!Number.isFinite(v)) return DEFAULT_VOLUME;
  return v < 0 ? 0 : v > 1 ? 1 : v;
}

function readFromStorage(): PlayerPreferences {
  if (typeof window === 'undefined') {
    return { volume: DEFAULT_VOLUME, muted: DEFAULT_MUTED };
  }
  try {
    const raw = window.localStorage.getItem(STORAGE_KEY);
    if (!raw) return { volume: DEFAULT_VOLUME, muted: DEFAULT_MUTED };
    const parsed = JSON.parse(raw) as Partial<PlayerPreferences> | null;
    return {
      volume: typeof parsed?.volume === 'number' ? clamp01(parsed.volume) : DEFAULT_VOLUME,
      muted: typeof parsed?.muted === 'boolean' ? parsed.muted : DEFAULT_MUTED,
    };
  } catch {
    return { volume: DEFAULT_VOLUME, muted: DEFAULT_MUTED };
  }
}

function writeToStorage(prefs: PlayerPreferences): void {
  if (typeof window === 'undefined') return;
  try {
    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs));
  } catch {
    // quota exceeded / disabled — silently ignore.
  }
}

function bindStorage(): void {
  if (storageBound || typeof window === 'undefined') return;
  storageBound = true;
  window.addEventListener('storage', (e) => {
    if (e.key !== STORAGE_KEY) return;
    cached = readFromStorage();
    for (const cb of listeners) cb(cached);
  });
}

export function getPreferences(): PlayerPreferences {
  if (!cached) cached = readFromStorage();
  bindStorage();
  return cached;
}

function update(next: PlayerPreferences, persist = true): void {
  cached = next;
  if (persist) writeToStorage(next);
  for (const cb of listeners) cb(next);
}

export function setStoredVolume(volume: number): void {
  const current = getPreferences();
  const v = clamp01(volume);
  if (v === current.volume) return;
  update({ ...current, volume: v });
}

export function setStoredMuted(muted: boolean): void {
  const current = getPreferences();
  if (muted === current.muted) return;
  update({ ...current, muted });
}

export function subscribePreferences(cb: Listener): () => void {
  listeners.add(cb);
  bindStorage();
  return () => listeners.delete(cb);
}

// Test-only.
export function _resetPreferencesForTesting(): void {
  cached = null;
  if (typeof window !== 'undefined') {
    try {
      window.localStorage.removeItem(STORAGE_KEY);
    } catch {
      // ignore
    }
  }
}
