const SOUND_VOLUME_STORAGE_KEY = "ld59.sound.volume";
const DEFAULT_SOUND_VOLUME = 0.5;

export class Sound {
    constructor() {
        const { volume, hasStoredVolume } = this.loadVolumeState();
        this.volume = volume;
        this.hasStoredVolume = hasStoredVolume;
        this.changeListeners = new Set();
    }

    clampVolume(value) {
        const normalizedValue = Number.isFinite(value) ? value : 0;
        const clampedValue = Math.min(1, Math.max(0, normalizedValue));

        if (clampedValue <= 0.02) {
            return 0;
        }

        if (clampedValue >= 0.98) {
            return 1;
        }

        return Math.round(clampedValue * 100) / 100;
    }

    loadVolumeState() {
        try {
            const storedVolume = window.localStorage.getItem(SOUND_VOLUME_STORAGE_KEY);
            if (storedVolume === null) {
                return {
                    volume: DEFAULT_SOUND_VOLUME,
                    hasStoredVolume: false
                };
            }

            return {
                volume: this.clampVolume(Number.parseFloat(storedVolume)),
                hasStoredVolume: true
            };
        } catch {
            return {
                volume: DEFAULT_SOUND_VOLUME,
                hasStoredVolume: false
            };
        }
    }

    saveVolume() {
        try {
            window.localStorage.setItem(SOUND_VOLUME_STORAGE_KEY, String(this.volume));
        } catch {
            return;
        }
    }

    addChangeListener(listener) {
        if (typeof listener !== "function") {
            return () => {};
        }

        this.changeListeners.add(listener);
        return () => {
            this.changeListeners.delete(listener);
        };
    }

    notifyChangeListeners() {
        for (const listener of this.changeListeners) {
            try {
                listener(this.volume);
            } catch {
                continue;
            }
        }
    }

    setInitialVolume(value) {
        const nextVolume = this.clampVolume(value);
        if (this.volume === nextVolume) {
            return this.volume;
        }

        this.volume = nextVolume;
        this.hasStoredVolume = true;
        this.saveVolume();
        this.notifyChangeListeners();
        return this.volume;
    }

    setVolume(value) {
        const nextVolume = this.clampVolume(value);

        if (this.volume === nextVolume) {
            return this.volume;
        }

        this.volume = nextVolume;
        this.hasStoredVolume = true;
        this.saveVolume();
        this.notifyChangeListeners();
        return this.volume;
    }

    getVolume() {
        return this.volume;
    }

    getScaledVolume(multiplier = 1) {
        const normalizedMultiplier = Number.isFinite(multiplier) ? multiplier : 1;
        return Math.min(1, Math.max(0, this.volume * Math.min(1, Math.max(0, normalizedMultiplier))));
    }
}

export const sound = new Sound();