export type AudioCueKey =
  | 'session_started'
  | 'control_completed:start'
  | 'control_completed:control'
  | 'control_completed:finish'
  | 'punch_feedback:warning'
  | 'guidance:searching'
  | 'guidance:distant'
  | 'guidance:approaching'
  | 'guidance:ready'

export interface AudioCueConfig {
  src: string
  volume: number
  loop: boolean
  loopGapMs: number
  backgroundMode: 'disabled' | 'guidance'
}

export interface GameAudioConfig {
  enabled: boolean
  masterVolume: number
  obeyMuteSwitch: boolean
  backgroundAudioEnabled: boolean
  distantDistanceMeters: number
  approachDistanceMeters: number
  readyDistanceMeters: number
  cues: Record<AudioCueKey, AudioCueConfig>
}

export interface PartialAudioCueConfig {
  src?: string
  volume?: number
  loop?: boolean
  loopGapMs?: number
  backgroundMode?: 'disabled' | 'guidance'
}

export interface GameAudioConfigOverrides {
  enabled?: boolean
  masterVolume?: number
  obeyMuteSwitch?: boolean
  backgroundAudioEnabled?: boolean
  distantDistanceMeters?: number
  approachDistanceMeters?: number
  readyDistanceMeters?: number
  cues?: Partial<Record<AudioCueKey, PartialAudioCueConfig>>
}

export const DEFAULT_GAME_AUDIO_CONFIG: GameAudioConfig = {
  enabled: true,
  masterVolume: 1,
  obeyMuteSwitch: true,
  backgroundAudioEnabled: true,
  distantDistanceMeters: 80,
  approachDistanceMeters: 20,
  readyDistanceMeters: 5,
  cues: {
    session_started: {
      src: '/assets/sounds/session-start.wav',
      volume: 0.78,
      loop: false,
      loopGapMs: 0,
      backgroundMode: 'disabled',
    },
    'control_completed:start': {
      src: '/assets/sounds/start-complete.wav',
      volume: 0.84,
      loop: false,
      loopGapMs: 0,
      backgroundMode: 'disabled',
    },
    'control_completed:control': {
      src: '/assets/sounds/control-complete.wav',
      volume: 0.8,
      loop: false,
      loopGapMs: 0,
      backgroundMode: 'disabled',
    },
    'control_completed:finish': {
      src: '/assets/sounds/finish-complete.wav',
      volume: 0.92,
      loop: false,
      loopGapMs: 0,
      backgroundMode: 'disabled',
    },
    'punch_feedback:warning': {
      src: '/assets/sounds/warning.wav',
      volume: 0.72,
      loop: false,
      loopGapMs: 0,
      backgroundMode: 'disabled',
    },
    'guidance:searching': {
      src: '/assets/sounds/guidance-searching.wav',
      volume: 0.48,
      loop: true,
      loopGapMs: 1800,
      backgroundMode: 'guidance',
    },
    'guidance:distant': {
      src: '/assets/sounds/guidance-searching.wav',
      volume: 0.34,
      loop: true,
      loopGapMs: 4800,
      backgroundMode: 'guidance',
    },
    'guidance:approaching': {
      src: '/assets/sounds/guidance-approaching.wav',
      volume: 0.58,
      loop: true,
      loopGapMs: 950,
      backgroundMode: 'guidance',
    },
    'guidance:ready': {
      src: '/assets/sounds/guidance-ready.wav',
      volume: 0.68,
      loop: true,
      loopGapMs: 650,
      backgroundMode: 'guidance',
    },
  },
}

function clampVolume(value: number, fallback: number): number {
  return Number.isFinite(value) ? Math.max(0, Math.min(1, value)) : fallback
}

function clampDistance(value: number, fallback: number): number {
  return Number.isFinite(value) && value > 0 ? value : fallback
}


function clampGap(value: number, fallback: number): number {
  return Number.isFinite(value) && value >= 0 ? value : fallback
}

export function mergeGameAudioConfig(overrides?: GameAudioConfigOverrides | null): GameAudioConfig {
  const cues: GameAudioConfig['cues'] = {
    session_started: { ...DEFAULT_GAME_AUDIO_CONFIG.cues.session_started },
    'control_completed:start': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['control_completed:start'] },
    'control_completed:control': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['control_completed:control'] },
    'control_completed:finish': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['control_completed:finish'] },
    'punch_feedback:warning': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['punch_feedback:warning'] },
    'guidance:searching': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['guidance:searching'] },
    'guidance:distant': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['guidance:distant'] },
    'guidance:approaching': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['guidance:approaching'] },
    'guidance:ready': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['guidance:ready'] },
  }

  if (overrides && overrides.cues) {
    const keys = Object.keys(overrides.cues) as AudioCueKey[]
    for (const key of keys) {
      const cue = overrides.cues[key]
      if (!cue) {
        continue
      }

      if (typeof cue.src === 'string' && cue.src) {
        cues[key].src = cue.src
      }

      if (cue.volume !== undefined) {
        cues[key].volume = clampVolume(Number(cue.volume), cues[key].volume)
      }

      if (cue.loop !== undefined) {
        cues[key].loop = !!cue.loop
      }

      if (cue.loopGapMs !== undefined) {
        cues[key].loopGapMs = clampGap(Number(cue.loopGapMs), cues[key].loopGapMs)
      }

      if (cue.backgroundMode === 'disabled' || cue.backgroundMode === 'guidance') {
        cues[key].backgroundMode = cue.backgroundMode
      }
    }
  }

  return {
    enabled: overrides && overrides.enabled !== undefined ? !!overrides.enabled : DEFAULT_GAME_AUDIO_CONFIG.enabled,
    masterVolume: clampVolume(Number(overrides && overrides.masterVolume), DEFAULT_GAME_AUDIO_CONFIG.masterVolume),
    obeyMuteSwitch: overrides && overrides.obeyMuteSwitch !== undefined ? !!overrides.obeyMuteSwitch : DEFAULT_GAME_AUDIO_CONFIG.obeyMuteSwitch,
    backgroundAudioEnabled: overrides && overrides.backgroundAudioEnabled !== undefined
      ? !!overrides.backgroundAudioEnabled
      : true,
    distantDistanceMeters: clampDistance(
      Number(overrides && overrides.distantDistanceMeters),
      DEFAULT_GAME_AUDIO_CONFIG.distantDistanceMeters,
    ),
    approachDistanceMeters: clampDistance(Number(overrides && overrides.approachDistanceMeters), DEFAULT_GAME_AUDIO_CONFIG.approachDistanceMeters),
    readyDistanceMeters: clampDistance(
      Number(overrides && overrides.readyDistanceMeters),
      DEFAULT_GAME_AUDIO_CONFIG.readyDistanceMeters,
    ),
    cues,
  }
}
