/**
 * Sound Notifications
 *
 * Optional sound notifications for events:
 * - Task completion
 * - Errors
 * - User attention needed
 * - Success/failure indicators
 */
import { exec } from 'child_process';
import * as os from 'os';
import fs from 'fs-extra';
import * as path from 'path';
import { logger } from '../utils/logger.js';
const DEFAULT_CONFIG = {
    enabled: true,
    volume: 50,
    customSounds: {
        success: undefined,
        error: undefined,
        warning: undefined,
        info: undefined,
        complete: undefined,
        attention: undefined,
        message: undefined,
        bell: undefined,
    },
    mutedTimes: [],
};
/**
 * Terminal bell frequencies for different sounds (Hz)
 */
const SOUND_FREQUENCIES = {
    success: [523, 659, 784], // C5, E5, G5 - happy chord
    error: [262, 196], // C4, G3 - descending
    warning: [440, 440], // A4, A4 - double beep
    info: [523], // C5 - single
    complete: [523, 659, 784, 1047], // C5, E5, G5, C6 - ascending
    attention: [880, 880, 880], // A5 triple
    message: [440, 523], // A4, C5 - ascending
    bell: [440], // A4 - standard bell
};
/**
 * Sound Notification Manager
 */
export class SoundNotificationManager {
    config;
    configPath;
    platform;
    constructor(configPath) {
        this.configPath = configPath || path.join(os.homedir(), '.codebuddy', 'sounds.json');
        this.config = { ...DEFAULT_CONFIG };
        this.platform = os.platform();
        this.loadConfig();
    }
    /**
     * Play a notification sound
     */
    async play(sound) {
        if (!this.config.enabled)
            return;
        if (this.isMuted())
            return;
        // Check for custom sound file
        const customPath = this.config.customSounds[sound];
        if (customPath && await fs.pathExists(customPath)) {
            await this.playFile(customPath);
            return;
        }
        // Use system sounds
        await this.playSystemSound(sound);
    }
    /**
     * Play success sound
     */
    async success() {
        await this.play('success');
    }
    /**
     * Play error sound
     */
    async error() {
        await this.play('error');
    }
    /**
     * Play warning sound
     */
    async warning() {
        await this.play('warning');
    }
    /**
     * Play info sound
     */
    async info() {
        await this.play('info');
    }
    /**
     * Play completion sound
     */
    async complete() {
        await this.play('complete');
    }
    /**
     * Play attention sound
     */
    async attention() {
        await this.play('attention');
    }
    /**
     * Play message sound
     */
    async message() {
        await this.play('message');
    }
    /**
     * Play bell
     */
    async bell() {
        await this.play('bell');
    }
    /**
     * Simple terminal bell (works everywhere)
     */
    async terminalBell() {
        if (!this.config.enabled)
            return;
        if (this.isMuted())
            return;
        process.stdout.write('\x07');
    }
    /**
     * Enable/disable sounds
     */
    setEnabled(enabled) {
        this.config.enabled = enabled;
        this.saveConfig();
    }
    /**
     * Check if enabled
     */
    isEnabled() {
        return this.config.enabled;
    }
    /**
     * Set volume
     */
    setVolume(volume) {
        this.config.volume = Math.max(0, Math.min(100, volume));
        this.saveConfig();
    }
    /**
     * Get volume
     */
    getVolume() {
        return this.config.volume;
    }
    /**
     * Set custom sound file
     */
    async setCustomSound(sound, filePath) {
        if (!await fs.pathExists(filePath)) {
            return false;
        }
        this.config.customSounds[sound] = filePath;
        this.saveConfig();
        return true;
    }
    /**
     * Clear custom sound
     */
    clearCustomSound(sound) {
        this.config.customSounds[sound] = undefined;
        this.saveConfig();
    }
    /**
     * Add muted time range
     */
    addMutedTime(range) {
        if (!this.config.mutedTimes.includes(range)) {
            this.config.mutedTimes.push(range);
            this.saveConfig();
        }
    }
    /**
     * Remove muted time range
     */
    removeMutedTime(range) {
        this.config.mutedTimes = this.config.mutedTimes.filter(t => t !== range);
        this.saveConfig();
    }
    /**
     * Check if currently muted by time
     */
    isMuted() {
        const now = new Date();
        const currentMinutes = now.getHours() * 60 + now.getMinutes();
        for (const range of this.config.mutedTimes) {
            const [start, end] = range.split('-');
            if (!start || !end)
                continue;
            const [startH, startM] = start.split(':').map(Number);
            const [endH, endM] = end.split(':').map(Number);
            const startMinutes = startH * 60 + startM;
            const endMinutes = endH * 60 + endM;
            if (startMinutes <= endMinutes) {
                // Same day range
                if (currentMinutes >= startMinutes && currentMinutes <= endMinutes) {
                    return true;
                }
            }
            else {
                // Overnight range (e.g., 22:00-08:00)
                if (currentMinutes >= startMinutes || currentMinutes <= endMinutes) {
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * Get config
     */
    getConfig() {
        return { ...this.config };
    }
    /**
     * Test all sounds
     */
    async testAllSounds() {
        const sounds = [
            'bell', 'info', 'message', 'warning', 'success', 'error', 'complete', 'attention'
        ];
        for (const sound of sounds) {
            logger.info(`Playing: ${sound}`);
            await this.play(sound);
            await new Promise(resolve => setTimeout(resolve, 500));
        }
    }
    /**
     * Play a sound file
     */
    async playFile(filePath) {
        return new Promise((resolve) => {
            let command;
            switch (this.platform) {
                case 'darwin':
                    command = `afplay -v ${this.config.volume / 100} "${filePath}"`;
                    break;
                case 'win32':
                    command = `powershell -c "(New-Object Media.SoundPlayer '${filePath}').PlaySync()"`;
                    break;
                default: // Linux
                    command = `paplay "${filePath}" 2>/dev/null || aplay "${filePath}" 2>/dev/null || true`;
                    break;
            }
            exec(command, () => resolve());
        });
    }
    /**
     * Play system sound
     */
    async playSystemSound(sound) {
        const frequencies = SOUND_FREQUENCIES[sound];
        switch (this.platform) {
            case 'darwin':
                await this.playMacSound(frequencies);
                break;
            case 'win32':
                await this.playWindowsSound(frequencies);
                break;
            default:
                await this.playLinuxSound(frequencies);
                break;
        }
    }
    /**
     * Play sound on macOS
     */
    async playMacSound(frequencies) {
        // Use osascript to generate beeps
        const beeps = frequencies.map(_f => {
            return `beep`;
        }).join('; delay 0.1; ');
        return new Promise((resolve) => {
            exec(`osascript -e '${beeps}'`, () => resolve());
        });
    }
    /**
     * Play sound on Windows
     */
    async playWindowsSound(frequencies) {
        const beeps = frequencies.map(f => `[console]::beep(${f}, 100)`).join('; ');
        return new Promise((resolve) => {
            exec(`powershell -c "${beeps}"`, () => resolve());
        });
    }
    /**
     * Play sound on Linux
     */
    async playLinuxSound(frequencies) {
        // Try different methods
        const methods = [
            // paplay with system sounds
            () => {
                const soundFile = frequencies[0] > 500
                    ? '/usr/share/sounds/freedesktop/stereo/complete.oga'
                    : '/usr/share/sounds/freedesktop/stereo/bell.oga';
                return `paplay ${soundFile} 2>/dev/null`;
            },
            // Terminal bell
            () => {
                process.stdout.write('\x07');
                return 'true';
            },
        ];
        for (const method of methods) {
            const command = method();
            try {
                await new Promise((resolve, reject) => {
                    exec(command, (error) => {
                        if (error)
                            reject(error);
                        else
                            resolve();
                    });
                });
                return;
            }
            catch {
                continue;
            }
        }
        // Fallback: terminal bell
        process.stdout.write('\x07');
    }
    /**
     * Load config from file
     */
    loadConfig() {
        try {
            if (fs.existsSync(this.configPath)) {
                const data = fs.readJsonSync(this.configPath);
                this.config = { ...DEFAULT_CONFIG, ...data };
            }
        }
        catch {
            // Use defaults
        }
    }
    /**
     * Save config to file
     */
    saveConfig() {
        try {
            fs.ensureDirSync(path.dirname(this.configPath));
            fs.writeJsonSync(this.configPath, this.config, { spaces: 2 });
        }
        catch {
            // Ignore save errors
        }
    }
}
// Singleton instance
let soundManager = null;
/**
 * Get or create sound notification manager
 */
export function getSoundManager() {
    if (!soundManager) {
        soundManager = new SoundNotificationManager();
    }
    return soundManager;
}
/**
 * Quick sound helpers
 */
export async function playSuccess() {
    await getSoundManager().success();
}
export async function playError() {
    await getSoundManager().error();
}
export async function playWarning() {
    await getSoundManager().warning();
}
export async function playComplete() {
    await getSoundManager().complete();
}
export async function playBell() {
    await getSoundManager().bell();
}
export default SoundNotificationManager;
//# sourceMappingURL=sound-notifications.js.map