//
//  SoundManager.swift
//  lichunWebsocket
//
//  Sound effects management system
//

import AVFoundation
import SwiftUI

// MARK: - Game Sound Enum
enum GameSound {
    // UI Interactions
    case buttonTap
    case toggleSwitch
    case modalOpen
    case modalClose

    // Transactions
    case purchase
    case purchaseSuccess
    case purchaseFailed
    case coinEarned
    case diamondEarned

    // Notifications
    case notification
    case message
    case achievement

    // Feedback
    case success
    case error
    case warning

    // Game Events
    case levelUp
    case energyDepleted
    case relationshipIncrease
    case heartbeat

    var filename: String {
        switch self {
        // UI Interactions
        case .buttonTap: return "tap"
        case .toggleSwitch: return "switch"
        case .modalOpen: return "modal_open"
        case .modalClose: return "modal_close"

        // Transactions
        case .purchase: return "purchase"
        case .purchaseSuccess: return "purchase_success"
        case .purchaseFailed: return "purchase_failed"
        case .coinEarned: return "coin"
        case .diamondEarned: return "diamond"

        // Notifications
        case .notification: return "notification"
        case .message: return "message"
        case .achievement: return "achievement"

        // Feedback
        case .success: return "success"
        case .error: return "error"
        case .warning: return "warning"

        // Game Events
        case .levelUp: return "level_up"
        case .energyDepleted: return "energy_depleted"
        case .relationshipIncrease: return "relationship_up"
        case .heartbeat: return "heartbeat"
        }
    }

    var volume: Float {
        switch self {
        case .buttonTap, .toggleSwitch: return 0.3
        case .heartbeat: return 0.2
        case .energyDepleted, .warning: return 0.4
        default: return 0.5
        }
    }
}

// MARK: - Sound Manager
class SoundManager: ObservableObject {
    static let shared = SoundManager()

    @Published var isSoundEnabled: Bool {
        didSet {
            UserDefaults.standard.set(isSoundEnabled, forKey: "soundEnabled")
            if !isSoundEnabled {
                stopAllSounds()
            }
        }
    }

    @Published var soundVolume: Float {
        didSet {
            UserDefaults.standard.set(soundVolume, forKey: "soundVolume")
            updateAllVolumes()
        }
    }

    private var audioPlayers: [String: AVAudioPlayer] = [:]
    private var isAudioSessionConfigured = false

    private init() {
        self.isSoundEnabled = UserDefaults.standard.object(forKey: "soundEnabled") as? Bool ?? true
        self.soundVolume = UserDefaults.standard.object(forKey: "soundVolume") as? Float ?? 0.7
        configureAudioSession()
    }

    // MARK: - Public Methods

    /// Play a sound effect
    func playSound(_ sound: GameSound) {
        guard isSoundEnabled else { return }
        guard !isSilentMode() else { return }

        // Check if player already exists and is playing
        if let player = audioPlayers[sound.filename] {
            player.stop()
            player.currentTime = 0
            player.volume = sound.volume * soundVolume
            player.play()
        } else {
            loadAndPlay(sound)
        }
    }

    /// Play sound with completion handler
    func playSound(_ sound: GameSound, completion: (() -> Void)? = nil) {
        guard isSoundEnabled else {
            completion?()
            return
        }

        playSound(sound)

        // Estimate duration and call completion
        if let player = audioPlayers[sound.filename] {
            DispatchQueue.main.asyncAfter(deadline: .now() + player.duration) {
                completion?()
            }
        } else {
            completion?()
        }
    }

    /// Stop all playing sounds
    func stopAllSounds() {
        audioPlayers.values.forEach { player in
            player.stop()
        }
    }

    /// Preload a sound for better performance
    func preloadSound(_ sound: GameSound) {
        guard audioPlayers[sound.filename] == nil else { return }

        guard let url = Bundle.main.url(forResource: sound.filename, withExtension: "mp3") else {
            // Sound file not found - this is expected until audio files are added
            return
        }

        do {
            let player = try AVAudioPlayer(contentsOf: url)
            player.prepareToPlay()
            player.volume = sound.volume * soundVolume
            audioPlayers[sound.filename] = player
        } catch {
            print("Error preloading sound \(sound.filename): \(error.localizedDescription)")
        }
    }

    /// Preload multiple sounds
    func preloadSounds(_ sounds: [GameSound]) {
        sounds.forEach { preloadSound($0) }
    }

    // MARK: - Private Methods

    private func configureAudioSession() {
        guard !isAudioSessionConfigured else { return }

        do {
            // Configure audio session to respect silent mode
            try AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default)
            try AVAudioSession.sharedInstance().setActive(true)
            isAudioSessionConfigured = true
        } catch {
            print("Failed to configure audio session: \(error.localizedDescription)")
        }
    }

    private func loadAndPlay(_ sound: GameSound) {
        guard let url = Bundle.main.url(forResource: sound.filename, withExtension: "mp3") else {
            // Sound file not found - this is expected until audio files are added
            // In production, we would log this to analytics
            return
        }

        do {
            let player = try AVAudioPlayer(contentsOf: url)
            player.volume = sound.volume * soundVolume
            player.prepareToPlay()
            audioPlayers[sound.filename] = player
            player.play()
        } catch {
            print("Error playing sound \(sound.filename): \(error.localizedDescription)")
        }
    }

    private func updateAllVolumes() {
        audioPlayers.forEach { (key, player) in
            // Find the sound by filename to get its base volume
            if let sound = findSound(byFilename: key) {
                player.volume = sound.volume * soundVolume
            }
        }
    }

    private func findSound(byFilename filename: String) -> GameSound? {
        let allSounds: [GameSound] = [
            .buttonTap, .toggleSwitch, .modalOpen, .modalClose,
            .purchase, .purchaseSuccess, .purchaseFailed, .coinEarned, .diamondEarned,
            .notification, .message, .achievement,
            .success, .error, .warning,
            .levelUp, .energyDepleted, .relationshipIncrease, .heartbeat
        ]
        return allSounds.first { $0.filename == filename }
    }

    private func isSilentMode() -> Bool {
        // Respect iOS silent mode by using ambient audio category
        // The audio session is already configured to respect silent mode
        return false
    }
}

// MARK: - View Extension for Sound
extension View {
    /// Play sound on tap
    func soundOnTap(_ sound: GameSound) -> some View {
        self.simultaneousGesture(
            TapGesture().onEnded { _ in
                SoundManager.shared.playSound(sound)
            }
        )
    }

    /// Play sound when a value changes
    func soundOnChange<V: Equatable>(of value: V, sound: GameSound) -> some View {
        self.onChange(of: value) { _ in
            SoundManager.shared.playSound(sound)
        }
    }
}

// MARK: - Button Extension
struct SoundButton<Label: View>: View {
    let sound: GameSound
    let action: () -> Void
    let label: () -> Label

    init(
        sound: GameSound = .buttonTap,
        action: @escaping () -> Void,
        @ViewBuilder label: @escaping () -> Label
    ) {
        self.sound = sound
        self.action = action
        self.label = label
    }

    var body: some View {
        Button {
            SoundManager.shared.playSound(sound)
            action()
        } label: {
            label()
        }
    }
}

// MARK: - Preview
#if DEBUG
struct SoundManager_Previews: PreviewProvider {
    static var previews: some View {
        ScrollView {
            VStack(spacing: AppSpacing.md) {
                Text("Sound Manager Test")
                    .font(.appLargeTitle)
                    .padding()

                Toggle("Sound Enabled", isOn: .constant(true))
                    .padding(.horizontal)

                Divider()

                Group {
                    Text("UI Sounds")
                        .font(.appHeadline)

                    Button("Button Tap") {
                        SoundManager.shared.playSound(.buttonTap)
                    }

                    Button("Modal Open") {
                        SoundManager.shared.playSound(.modalOpen)
                    }
                }

                Divider()

                Group {
                    Text("Transaction Sounds")
                        .font(.appHeadline)

                    Button("Purchase Success") {
                        SoundManager.shared.playSound(.purchaseSuccess)
                    }

                    Button("Coin Earned") {
                        SoundManager.shared.playSound(.coinEarned)
                    }
                }

                Divider()

                Group {
                    Text("Feedback Sounds")
                        .font(.appHeadline)

                    Button("Success") {
                        SoundManager.shared.playSound(.success)
                    }

                    Button("Error") {
                        SoundManager.shared.playSound(.error)
                    }

                    Button("Warning") {
                        SoundManager.shared.playSound(.warning)
                    }
                }

                Divider()

                Group {
                    Text("Game Events")
                        .font(.appHeadline)

                    Button("Achievement") {
                        SoundManager.shared.playSound(.achievement)
                    }

                    Button("Level Up") {
                        SoundManager.shared.playSound(.levelUp)
                    }
                }
            }
            .padding()
        }
        .background(AppColors.background)
    }
}
#endif
