import type { TimerSoundType } from '@/shared/types/classroomTimer';

const connectTone = (
  audioCtx: AudioContext,
  oscillator: OscillatorNode,
  gain: GainNode,
) => {
  oscillator.connect(gain).connect(audioCtx.destination);
};

export function playBuiltInSound(soundType: TimerSoundType, audioCtx: AudioContext): void {
  const now = audioCtx.currentTime;

  switch (soundType) {
    case 'gentle-chime': {
      const frequencies = [523.25, 659.25, 783.99, 1046.5];
      frequencies.forEach((frequency, index) => {
        const oscillator = audioCtx.createOscillator();
        const gain = audioCtx.createGain();
        oscillator.type = 'sine';
        oscillator.frequency.value = frequency;
        gain.gain.setValueAtTime(0, now + index * 0.3);
        gain.gain.linearRampToValueAtTime(0.3, now + index * 0.3 + 0.05);
        gain.gain.exponentialRampToValueAtTime(0.001, now + index * 0.3 + 1.5);
        connectTone(audioCtx, oscillator, gain);
        oscillator.start(now + index * 0.3);
        oscillator.stop(now + index * 0.3 + 1.5);
      });
      return;
    }
    case 'soft-bell': {
      const oscillator = audioCtx.createOscillator();
      const gain = audioCtx.createGain();
      oscillator.type = 'sine';
      oscillator.frequency.value = 440;
      gain.gain.setValueAtTime(0.4, now);
      gain.gain.exponentialRampToValueAtTime(0.001, now + 3);
      connectTone(audioCtx, oscillator, gain);
      oscillator.start(now);
      oscillator.stop(now + 3);

      const overtone = audioCtx.createOscillator();
      const overtoneGain = audioCtx.createGain();
      overtone.type = 'sine';
      overtone.frequency.value = 880;
      overtoneGain.gain.setValueAtTime(0.15, now);
      overtoneGain.gain.exponentialRampToValueAtTime(0.001, now + 2);
      connectTone(audioCtx, overtone, overtoneGain);
      overtone.start(now);
      overtone.stop(now + 2);
      return;
    }
    case 'xylophone': {
      const notes = [523.25, 587.33, 659.25, 783.99, 880, 783.99, 659.25];
      notes.forEach((frequency, index) => {
        const oscillator = audioCtx.createOscillator();
        const gain = audioCtx.createGain();
        oscillator.type = 'triangle';
        oscillator.frequency.value = frequency;
        gain.gain.setValueAtTime(0, now + index * 0.15);
        gain.gain.linearRampToValueAtTime(0.35, now + index * 0.15 + 0.01);
        gain.gain.exponentialRampToValueAtTime(0.001, now + index * 0.15 + 0.6);
        connectTone(audioCtx, oscillator, gain);
        oscillator.start(now + index * 0.15);
        oscillator.stop(now + index * 0.15 + 0.6);
      });
      return;
    }
    case 'singing-bowl': {
      const oscillator = audioCtx.createOscillator();
      const gain = audioCtx.createGain();
      oscillator.type = 'sine';
      oscillator.frequency.value = 256;
      oscillator.frequency.linearRampToValueAtTime(260, now + 4);
      gain.gain.setValueAtTime(0, now);
      gain.gain.linearRampToValueAtTime(0.35, now + 0.3);
      gain.gain.setValueAtTime(0.35, now + 1);
      gain.gain.exponentialRampToValueAtTime(0.001, now + 5);
      connectTone(audioCtx, oscillator, gain);
      oscillator.start(now);
      oscillator.stop(now + 5);

      const harmonic = audioCtx.createOscillator();
      const harmonicGain = audioCtx.createGain();
      harmonic.type = 'sine';
      harmonic.frequency.value = 512;
      harmonicGain.gain.setValueAtTime(0, now);
      harmonicGain.gain.linearRampToValueAtTime(0.1, now + 0.3);
      harmonicGain.gain.exponentialRampToValueAtTime(0.001, now + 4);
      connectTone(audioCtx, harmonic, harmonicGain);
      harmonic.start(now);
      harmonic.stop(now + 4);
      return;
    }
    case 'harp-gliss': {
      const scale = [261.63, 293.66, 329.63, 349.23, 392, 440, 493.88, 523.25, 587.33, 659.25, 698.46, 783.99];
      scale.forEach((frequency, index) => {
        const oscillator = audioCtx.createOscillator();
        const gain = audioCtx.createGain();
        oscillator.type = 'sine';
        oscillator.frequency.value = frequency;
        gain.gain.setValueAtTime(0, now + index * 0.08);
        gain.gain.linearRampToValueAtTime(0.2, now + index * 0.08 + 0.02);
        gain.gain.exponentialRampToValueAtTime(0.001, now + index * 0.08 + 1.2);
        connectTone(audioCtx, oscillator, gain);
        oscillator.start(now + index * 0.08);
        oscillator.stop(now + index * 0.08 + 1.2);
      });
      return;
    }
    case 'nature-birds':
    case 'ocean-wave':
    case 'rain-stick': {
      const oscillator = audioCtx.createOscillator();
      const gain = audioCtx.createGain();
      oscillator.type = 'sine';
      oscillator.frequency.value = 523.25;
      gain.gain.setValueAtTime(0.3, now);
      gain.gain.exponentialRampToValueAtTime(0.001, now + 2);
      connectTone(audioCtx, oscillator, gain);
      oscillator.start(now);
      oscillator.stop(now + 2);
      return;
    }
  }
}
