/**
 * Web Audio API Integration Service
 * Handles sound effects, music, and audio management for games
 */

import { EventEmitter } from 'events';

export interface AudioAsset {
  id: string;
  name: string;
  type: 'effect' | 'music' | 'voice';
  url: string;
  duration: number;
  volume: number;
  loop: boolean;
}

export interface AudioConfig {
  masterVolume: number;
  effectsVolume: number;
  musicVolume: number;
  voiceVolume: number;
  muted: boolean;
}

export class WebAudioIntegration extends EventEmitter {
  private audioAssets: Map<string, AudioAsset> = new Map();
  private audioConfig: AudioConfig = {
    masterVolume: 0.8,
    effectsVolume: 0.8,
    musicVolume: 0.6,
    voiceVolume: 0.8,
    muted: false,
  };

  private defaultSounds = {
    reelSpin: {
      id: 'sound-reel-spin',
      name: 'Reel Spin',
      type: 'effect' as const,
      url: '/sounds/reel-spin.mp3',
      duration: 0.5,
      volume: 0.7,
      loop: false,
    },
    reelStop: {
      id: 'sound-reel-stop',
      name: 'Reel Stop',
      type: 'effect' as const,
      url: '/sounds/reel-stop.mp3',
      duration: 0.3,
      volume: 0.6,
      loop: false,
    },
    winChime: {
      id: 'sound-win-chime',
      name: 'Win Chime',
      type: 'effect' as const,
      url: '/sounds/win-chime.mp3',
      duration: 1.0,
      volume: 0.8,
      loop: false,
    },
    bigWinFanfare: {
      id: 'sound-big-win-fanfare',
      name: 'Big Win Fanfare',
      type: 'effect' as const,
      url: '/sounds/big-win-fanfare.mp3',
      duration: 2.0,
      volume: 1.0,
      loop: false,
    },
    jackpotWin: {
      id: 'sound-jackpot-win',
      name: 'Jackpot Win',
      type: 'effect' as const,
      url: '/sounds/jackpot-win.mp3',
      duration: 3.0,
      volume: 1.0,
      loop: false,
    },
    bonusRoundStart: {
      id: 'sound-bonus-round-start',
      name: 'Bonus Round Start',
      type: 'effect' as const,
      url: '/sounds/bonus-round-start.mp3',
      duration: 1.5,
      volume: 0.8,
      loop: false,
    },
    freeSpinsStart: {
      id: 'sound-free-spins-start',
      name: 'Free Spins Start',
      type: 'effect' as const,
      url: '/sounds/free-spins-start.mp3',
      duration: 1.2,
      volume: 0.8,
      loop: false,
    },
    backgroundMusic: {
      id: 'sound-background-music',
      name: 'Background Music',
      type: 'music' as const,
      url: '/sounds/background-music.mp3',
      duration: 60.0,
      volume: 0.4,
      loop: true,
    },
    buttonClick: {
      id: 'sound-button-click',
      name: 'Button Click',
      type: 'effect' as const,
      url: '/sounds/button-click.mp3',
      duration: 0.1,
      volume: 0.5,
      loop: false,
    },
  };

  constructor() {
    super();
    this.initializeDefaultSounds();
  }

  /**
   * Initialize default sounds
   */
  private initializeDefaultSounds(): void {
    Object.values(this.defaultSounds).forEach((sound) => {
      this.audioAssets.set(sound.id, sound);
    });
    this.emit('sounds_initialized', { count: this.audioAssets.size });
  }

  /**
   * Register custom audio asset
   */
  registerAudioAsset(asset: AudioAsset): void {
    this.audioAssets.set(asset.id, asset);
    this.emit('asset_registered', asset);
  }

  /**
   * Get audio asset
   */
  getAudioAsset(assetId: string): AudioAsset | undefined {
    return this.audioAssets.get(assetId);
  }

  /**
   * Get all audio assets
   */
  getAllAudioAssets(): AudioAsset[] {
    return Array.from(this.audioAssets.values());
  }

  /**
   * Play sound effect
   */
  playEffect(effectId: string, volume?: number): void {
    const asset = this.audioAssets.get(effectId);
    if (!asset) {
      console.warn(`Audio asset not found: ${effectId}`);
      return;
    }

    const finalVolume = this.calculateFinalVolume(
      volume || asset.volume,
      'effect'
    );

    this.emit('play_effect', {
      assetId: effectId,
      volume: finalVolume,
      timestamp: Date.now(),
    });
  }

  /**
   * Play background music
   */
  playMusic(musicId: string, volume?: number): void {
    const asset = this.audioAssets.get(musicId);
    if (!asset || asset.type !== 'music') {
      console.warn(`Music asset not found: ${musicId}`);
      return;
    }

    const finalVolume = this.calculateFinalVolume(volume || asset.volume, 'music');

    this.emit('play_music', {
      assetId: musicId,
      volume: finalVolume,
      loop: asset.loop,
      timestamp: Date.now(),
    });
  }

  /**
   * Stop all audio
   */
  stopAll(): void {
    this.emit('stop_all', { timestamp: Date.now() });
  }

  /**
   * Stop specific audio
   */
  stopAudio(assetId: string): void {
    this.emit('stop_audio', { assetId, timestamp: Date.now() });
  }

  /**
   * Calculate final volume with master volume
   */
  private calculateFinalVolume(baseVolume: number, type: 'effect' | 'music' | 'voice'): number {
    if (this.audioConfig.muted) {
      return 0;
    }

    const typeVolume =
      type === 'effect'
        ? this.audioConfig.effectsVolume
        : type === 'music'
          ? this.audioConfig.musicVolume
          : this.audioConfig.voiceVolume;

    return (baseVolume * typeVolume * this.audioConfig.masterVolume) / 100;
  }

  /**
   * Set master volume
   */
  setMasterVolume(volume: number): void {
    this.audioConfig.masterVolume = Math.max(0, Math.min(1, volume));
    this.emit('volume_changed', { type: 'master', volume: this.audioConfig.masterVolume });
  }

  /**
   * Set effects volume
   */
  setEffectsVolume(volume: number): void {
    this.audioConfig.effectsVolume = Math.max(0, Math.min(1, volume));
    this.emit('volume_changed', { type: 'effects', volume: this.audioConfig.effectsVolume });
  }

  /**
   * Set music volume
   */
  setMusicVolume(volume: number): void {
    this.audioConfig.musicVolume = Math.max(0, Math.min(1, volume));
    this.emit('volume_changed', { type: 'music', volume: this.audioConfig.musicVolume });
  }

  /**
   * Toggle mute
   */
  toggleMute(): boolean {
    this.audioConfig.muted = !this.audioConfig.muted;
    this.emit('mute_toggled', { muted: this.audioConfig.muted });
    return this.audioConfig.muted;
  }

  /**
   * Get audio config
   */
  getAudioConfig(): AudioConfig {
    return { ...this.audioConfig };
  }

  /**
   * Play reel spin sound
   */
  playReelSpin(): void {
    this.playEffect('sound-reel-spin');
  }

  /**
   * Play reel stop sound
   */
  playReelStop(): void {
    this.playEffect('sound-reel-stop');
  }

  /**
   * Play win sound
   */
  playWinSound(isJackpot: boolean = false): void {
    if (isJackpot) {
      this.playEffect('sound-jackpot-win');
    } else {
      this.playEffect('sound-win-chime');
    }
  }

  /**
   * Play big win fanfare
   */
  playBigWinFanfare(): void {
    this.playEffect('sound-big-win-fanfare');
  }

  /**
   * Play bonus round start
   */
  playBonusRoundStart(): void {
    this.playEffect('sound-bonus-round-start');
  }

  /**
   * Play free spins start
   */
  playFreeSpinsStart(): void {
    this.playEffect('sound-free-spins-start');
  }

  /**
   * Play background music
   */
  playBackgroundMusic(): void {
    this.playMusic('sound-background-music');
  }

  /**
   * Play button click
   */
  playButtonClick(): void {
    this.playEffect('sound-button-click', 0.3);
  }

  /**
   * Create sound sequence
   */
  playSoundSequence(soundIds: string[], delays: number[] = []): void {
    soundIds.forEach((soundId, index) => {
      const delay = delays[index] || 0;
      setTimeout(() => {
        const asset = this.audioAssets.get(soundId);
        if (asset) {
          if (asset.type === 'music') {
            this.playMusic(soundId);
          } else {
            this.playEffect(soundId);
          }
        }
      }, delay);
    });
  }

  /**
   * Get sound library for frontend
   */
  getSoundLibrary(): Record<string, AudioAsset> {
    const library: Record<string, AudioAsset> = {};
    this.audioAssets.forEach((asset) => {
      library[asset.id] = asset;
    });
    return library;
  }
}

export const webAudioIntegration = new WebAudioIntegration();
