import AppKit
import NucleicCore

/// Plays a macOS system sound when a chat finishes its work or starts needing the
/// user. Installed on `AppStore.chatStatusSoundHook` at launch (see `NucleicApp.init`),
/// so it fires only on live transitions — never on launch/resume. Each one-shot cue has
/// its own on/off switch in Settings ▸ Chats, both on by default; a separate, off-by-default
/// "escalating alarm" (driven by `ChatAlarm`) instead *repeats* until the user returns to
/// the chat that needs them.
enum ChatStatusSounds {
    /// `@AppStorage` keys for the cues. The two one-shot cues default *on*, so we read with
    /// the `object(forKey:) as? Bool ?? true` dance: until the Settings view first binds (and
    /// writes a value), the key is unset, and a plain `bool(forKey:)` would read `false` —
    /// silencing the cue before the user has ever opened Settings. The escalating alarm is the
    /// opposite — strictly opt-in — so it defaults *off* (`?? false`).
    static let playOnDoneKey = "nucleic.chat.sound.done"
    static let playOnBlockedKey = "nucleic.chat.sound.blocked"
    static let escalatingAlarmKey = "nucleic.chat.sound.alarm"

    static var playOnDone: Bool {
        UserDefaults.standard.object(forKey: playOnDoneKey) as? Bool ?? true
    }
    static var playOnBlocked: Bool {
        UserDefaults.standard.object(forKey: playOnBlockedKey) as? Bool ?? true
    }
    static var escalatingAlarm: Bool {
        UserDefaults.standard.object(forKey: escalatingAlarmKey) as? Bool ?? false
    }

    /// macOS system sounds (in /System/Library/Sounds), resolved by name. "Funk" marks
    /// a finished chat; "Pop" marks one that now needs the user; "Submarine" is the
    /// escalating alarm's repeating pulse (played by `ChatAlarm`, not `play(_:)`).
    private static let doneSoundName = "Funk"
    private static let blockedSoundName = "Pop"
    static let alarmSoundName = "Submarine"

    /// Sound the cue for a settled chat transition, if its switch is on. Plays a fresh
    /// copy each time so back-to-back cues (e.g. two chats finishing at once) overlap
    /// rather than the second silently no-op'ing on an already-playing shared instance.
    @MainActor
    static func play(_ sound: ChatStatusSound) {
        let (enabled, name): (Bool, String)
        switch sound {
        case .done: (enabled, name) = (playOnDone, doneSoundName)
        case .blocked: (enabled, name) = (playOnBlocked, blockedSoundName)
        }
        guard enabled, let base = NSSound(named: NSSound.Name(name)) else { return }
        (base.copy() as? NSSound)?.play()
    }
}
