// Audio quality preferences for outgoing voice/music. `voice` is the default
// — Opus 48 kbps stereo with full DSP (echo cancellation + noise suppression
// + AGC). `hifi` bumps to 96 kbps stereo Opus and disables all DSP so music,
// instruments, or broadcast-style voice streams stay uncoloured.

const STORAGE_KEY = 'chatapp.audio';

export type AudioQuality = 'voice' | 'hifi';

export interface AudioSettings {
  quality: AudioQuality;
}

const DEFAULTS: AudioSettings = {
  quality: 'voice',
};

export interface AudioQualityParams {
  label: string;
  bitrateKbps: number;
  stereo: boolean;
  sampleRateHz: number;
  // DSP toggles — off for hifi so music isn't coloured by noise-suppression.
  echoCancellation: boolean;
  noiseSuppression: boolean;
  autoGainControl: boolean;
}

const PARAMS: Record<AudioQuality, AudioQualityParams> = {
  voice: {
    label: 'Voice · 48 kbps',
    bitrateKbps: 48,
    stereo: false,
    sampleRateHz: 48_000,
    echoCancellation: true,
    noiseSuppression: true,
    autoGainControl: true,
  },
  hifi: {
    label: 'HiFi · 510 kbps Stereo',
    bitrateKbps: 510, // Opus max, ~CD-quality stereo
    stereo: true,
    sampleRateHz: 48_000,
    echoCancellation: false,
    noiseSuppression: false,
    autoGainControl: false,
  },
};

export const AUDIO_QUALITY_ORDER: ReadonlyArray<AudioQuality> = ['voice', 'hifi'];

export function getAudioQualityParams(q: AudioQuality): AudioQualityParams {
  return PARAMS[q];
}

type Listener = (s: AudioSettings) => void;
const listeners = new Set<Listener>();

let cached: AudioSettings | null = null;

function isQuality(v: unknown): v is AudioQuality {
  return v === 'voice' || v === 'hifi';
}

function read(): AudioSettings {
  if (cached) return cached;
  try {
    const raw = window.localStorage.getItem(STORAGE_KEY);
    if (!raw) {
      cached = DEFAULTS;
      return cached;
    }
    const parsed = JSON.parse(raw) as Partial<AudioSettings>;
    cached = {
      quality: isQuality(parsed.quality) ? parsed.quality : DEFAULTS.quality,
    };
    return cached;
  } catch {
    cached = DEFAULTS;
    return cached;
  }
}

function write(s: AudioSettings): void {
  cached = s;
  try {
    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(s));
  } catch {
    /* quota / private mode */
  }
  for (const l of listeners) l(s);
}

export function getAudioSettings(): AudioSettings {
  return read();
}

export function updateAudioSettings(patch: Partial<AudioSettings>): AudioSettings {
  const next = { ...read(), ...patch };
  write(next);
  return next;
}

export function subscribeAudioSettings(listener: Listener): () => void {
  listeners.add(listener);
  return () => listeners.delete(listener);
}
