export class AmbientSoundPlayer {
    private audioCtx: AudioContext | null = null;
    private noiseSource: AudioBufferSourceNode | null = null;
    private gainNode: GainNode | null = null;
    private isPlaying = false;

    constructor() {
        // Initialize audio context only on user interaction to comply with browser policies
    }

    private initContext() {
        if (!this.audioCtx) {
            this.audioCtx = new (window.AudioContext || (window as any).webkitAudioContext)();
        }
    }

    private createBrownNoiseBuffer(): AudioBuffer {
        if (!this.audioCtx) throw new Error("No Audio Context");

        const bufferSize = this.audioCtx.sampleRate * 2; // 2 seconds buffer
        const buffer = this.audioCtx.createBuffer(1, bufferSize, this.audioCtx.sampleRate);
        const data = buffer.getChannelData(0);
        let lastOut = 0;

        for (let i = 0; i < bufferSize; i++) {
            const white = Math.random() * 2 - 1;
            data[i] = (lastOut + (0.02 * white)) / 1.02;
            lastOut = data[i];
            data[i] *= 3.5; // Compensate for gain loss
        }
        return buffer;
    }

    public toggle(type: 'brown' | 'white' = 'brown'): boolean {
        if (this.isPlaying) {
            this.stop();
            return false;
        } else {
            this.play(type);
            return true;
        }
    }

    public play(type: 'brown' | 'white' = 'brown') {
        this.initContext();
        if (!this.audioCtx) return;

        // Resume if suspended (browser autoplay policy)
        if (this.audioCtx.state === 'suspended') {
            this.audioCtx.resume();
        }

        this.stop(); // Stop any current sound

        this.noiseSource = this.audioCtx.createBufferSource();
        this.noiseSource.buffer = this.createBrownNoiseBuffer(); // Currently only brown noise implemented efficiently
        this.noiseSource.loop = true;

        this.gainNode = this.audioCtx.createGain();
        this.gainNode.gain.value = 0.5; // Default volume

        this.noiseSource.connect(this.gainNode);
        this.gainNode.connect(this.audioCtx.destination);

        // Fade in
        this.gainNode.gain.setValueAtTime(0, this.audioCtx.currentTime);
        this.gainNode.gain.linearRampToValueAtTime(0.5, this.audioCtx.currentTime + 1);

        this.noiseSource.start();
        this.isPlaying = true;
    }

    public stop() {
        if (this.noiseSource && this.gainNode && this.audioCtx) {
            // Fade out
            this.gainNode.gain.linearRampToValueAtTime(0, this.audioCtx.currentTime + 0.5);
            setTimeout(() => {
                this.noiseSource?.stop();
                this.noiseSource = null;
            }, 500);
        }
        this.isPlaying = false;
    }
}

export const ambientPlayer = new AmbientSoundPlayer();
