import type { AlarmPort } from '@domain/ports/AlarmPort';

export class WebAudioAlarm implements AlarmPort {
  private audioCtx: AudioContext | null = null;

  private ensureContext(): AudioContext {
    if (!this.audioCtx) {
      this.audioCtx = new AudioContext();
    }
    if (this.audioCtx.state === 'suspended') {
      this.audioCtx.resume();
    }
    return this.audioCtx;
  }

  play(soundName: string): void {
    const ctx = this.ensureContext();
    const doPlay = () => {
      if (soundName === 'arpege') {
        [440, 554, 659, 880].forEach((f, i) => setTimeout(() => {
          const o = ctx.createOscillator(), g = ctx.createGain();
          o.connect(g); g.connect(ctx.destination);
          o.frequency.value = f; o.type = 'sine';
          g.gain.setValueAtTime(0.35, ctx.currentTime);
          g.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.55);
          o.start(); o.stop(ctx.currentTime + 0.55);
        }, i * 140));
      } else if (soundName === 'pulse') {
        [0, 200, 400, 600, 800].forEach(ms => setTimeout(() => {
          const o = ctx.createOscillator(), g = ctx.createGain();
          o.connect(g); g.connect(ctx.destination);
          o.frequency.value = 880; o.type = 'square';
          g.gain.setValueAtTime(0.2, ctx.currentTime);
          g.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.15);
          o.start(); o.stop(ctx.currentTime + 0.15);
        }, ms));
      } else if (soundName === 'fanfare') {
        ([[523, 0], [659, 150], [784, 300], [1047, 500], [784, 700], [1047, 900]] as [number, number][]).forEach(([f, ms]) => setTimeout(() => {
          const o = ctx.createOscillator(), g = ctx.createGain();
          o.connect(g); g.connect(ctx.destination);
          o.frequency.value = f; o.type = 'triangle';
          g.gain.setValueAtTime(0.3, ctx.currentTime);
          g.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.18);
          o.start(); o.stop(ctx.currentTime + 0.18);
        }, ms));
      } else if (soundName === 'cloche') {
        const t = ctx.currentTime;
        ([[440, 1], [880, 0.6], [1320, 0.4], [1760, 0.25]] as [number, number][]).forEach(([f, v], i) => {
          const o = ctx.createOscillator(), g = ctx.createGain();
          o.connect(g); g.connect(ctx.destination);
          o.frequency.value = f; o.type = 'sine';
          g.gain.setValueAtTime(v * 0.3, t);
          g.gain.exponentialRampToValueAtTime(0.001, t + 2.5);
          o.start(t + i * 0.01); o.stop(t + 2.5);
        });
      } else {
        // Fallback : arpege
        this.play('arpege');
      }
    };
    if (ctx.state === 'suspended') {
      ctx.resume().then(doPlay).catch(() => {});
    } else {
      doPlay();
    }
  }

  stop(): void {
    if (this.audioCtx) {
      this.audioCtx.close();
      this.audioCtx = null;
    }
  }
}
