import Foundation
import Testing
import AVFoundation
@testable import Workouts

/// Locks the voice-resolution contract: the picker offers English voices, and the
/// announcer speaks with the user's stored choice when set, falling back to a valid
/// English voice otherwise.
struct SpeechSettingsTests {

    @Test func availableVoicesAreEnglish() {
        let voices = SpeechSettings.availableVoices()
        #expect(!voices.isEmpty)
        #expect(voices.allSatisfy { $0.language.hasPrefix("en") })
    }

    @Test func resolvedVoiceHonorsStoredIdentifierThenFallsBack() {
        let key = SpeechSettings.voiceIdentifierKey
        let original = UserDefaults.standard.string(forKey: key)
        defer {
            if let original { UserDefaults.standard.set(original, forKey: key) }
            else { UserDefaults.standard.removeObject(forKey: key) }
        }

        // Automatic (empty) resolves to some installed English voice.
        UserDefaults.standard.set("", forKey: key)
        let auto = SpeechSettings.resolvedVoice()
        #expect(auto != nil)
        #expect(auto?.language.hasPrefix("en") == true)

        // A specific installed voice resolves to exactly that voice.
        let target = try? #require(SpeechSettings.availableVoices().first)
        if let target {
            UserDefaults.standard.set(target.identifier, forKey: key)
            #expect(SpeechSettings.resolvedVoice()?.identifier == target.identifier)
        }
    }

    @Test func displayLabelAvoidsRedundantQualitySuffix() {
        // Default voices: name only, no "— Default" noise.
        #expect(SpeechSettings.displayLabel(name: "Samantha", quality: .default) == "Samantha")

        // Enhanced/premium voices get the tier appended when the name lacks it.
        #expect(SpeechSettings.displayLabel(name: "Samantha", quality: .enhanced) == "Samantha — Enhanced")

        // …but not when the name already carries it (e.g. "Ava (Premium)").
        #expect(SpeechSettings.displayLabel(name: "Ava (Premium)", quality: .premium) == "Ava (Premium)")
        #expect(SpeechSettings.displayLabel(name: "Daniel (Enhanced)", quality: .enhanced) == "Daniel (Enhanced)")
    }

    @Test func prosodyValuesClampToValidRanges() {
        let rateKey = SpeechSettings.rateKey
        let originalRate = UserDefaults.standard.object(forKey: rateKey) as? Double
        defer {
            if let originalRate { UserDefaults.standard.set(originalRate, forKey: rateKey) }
            else { UserDefaults.standard.removeObject(forKey: rateKey) }
        }

        // An out-of-range stored value is clamped, never passed raw to the utterance.
        UserDefaults.standard.set(99.0, forKey: rateKey)
        #expect(Double(SpeechSettings.rate) <= SpeechSettings.rateRange.upperBound)

        // A missing value resolves to the shared default.
        UserDefaults.standard.removeObject(forKey: rateKey)
        #expect(SpeechSettings.rate == Float(SpeechSettings.rateDefault))
    }
}
