package com.humand.demo.modules.Audio

import android.content.Context
import android.media.AudioAttributes
import android.media.AudioDeviceInfo
import android.media.AudioFocusRequest
import android.media.AudioManager
import android.os.Build
import android.util.Log

/**
 * Shared helper for audio session configuration used by CallManager/LivestreamManager
 * to centralize speaker/Bluetooth routing logic.
 */
class AudioSessionHelper private constructor(context: Context) {

    companion object {
        private const val TAG = "CallManager-Audio"

        @Volatile
        private var instance: AudioSessionHelper? = null

        fun getInstance(context: Context): AudioSessionHelper {
            return instance ?: synchronized(this) {
                instance ?: AudioSessionHelper(context.applicationContext).also { instance = it }
            }
        }
    }

    private val audioManager: AudioManager =
        context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
    private var audioFocusRequest: AudioFocusRequest? = null

    /**
     * Configure audio session for playback after call ends.
     * Routes to headphones/Bluetooth if connected, otherwise defaults to speaker.
     */
    fun configureForSpeaker() {
        val hasExternalDevice = isBluetoothOrHeadsetConnected()
        val hasExternalDisplay = isExternalDisplayConnected()
        Log.d(TAG, "Configuring audio session - hasExternalDevice: $hasExternalDevice, hasExternalDisplay: $hasExternalDisplay")

        try {
            // Request audio focus for media playback
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                // Abandon previous focus request if any
                audioFocusRequest?.let { audioManager.abandonAudioFocusRequest(it) }

                val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
                    .setAudioAttributes(
                        AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_MEDIA)
                            .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)
                            .build()
                    )
                    .build()
                audioFocusRequest = focusRequest
                audioManager.requestAudioFocus(focusRequest)
            }

            audioManager.mode = AudioManager.MODE_NORMAL

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                audioManager.clearCommunicationDevice()

                if (hasExternalDisplay) {
                    // External display (Chromecast/HDMI) connected — do NOT force speaker.
                    // Let Android's media routing send audio to the external display.
                    audioManager.isSpeakerphoneOn = false
                    Log.d(TAG, "Audio routed to external display (Chromecast/HDMI)")
                } else if (hasExternalDevice) {
                    // Let audio route to connected headphones/Bluetooth
                    audioManager.isSpeakerphoneOn = false
                    Log.d(TAG, "Audio routed to external device")
                } else {
                    // No external device, use speaker
                    val speakerDevice = audioManager.availableCommunicationDevices.firstOrNull {
                        it.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER
                    }
                    speakerDevice?.let { audioManager.setCommunicationDevice(it) }
                    audioManager.isSpeakerphoneOn = true
                    Log.d(TAG, "Audio routed to speaker")
                }
            } else {
                audioManager.isSpeakerphoneOn = !(hasExternalDevice || hasExternalDisplay)
                Log.d(TAG, "Audio routed to ${if (hasExternalDevice || hasExternalDisplay) "external device" else "speaker"} (legacy)")
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error configuring audio session: ${e.message}")
        }
    }

    private fun isBluetoothOrHeadsetConnected(): Boolean {
        val devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
        return devices.any {
            it.type == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP ||
            it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO ||
            it.type == AudioDeviceInfo.TYPE_WIRED_HEADSET ||
            it.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES ||
            it.type == AudioDeviceInfo.TYPE_USB_HEADSET
        }
    }

    /**
     * Check if an external media display (HDMI, Chromecast, etc.) is connected.
     * When casting, we should NOT force the communication device to speaker
     * as that prevents audio from routing through the external display.
     */
    fun isExternalDisplayConnected(): Boolean {
        val devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
        return devices.any {
            it.type == AudioDeviceInfo.TYPE_HDMI ||
            it.type == AudioDeviceInfo.TYPE_HDMI_ARC ||
            it.type == AudioDeviceInfo.TYPE_HDMI_EARC ||
            it.type == AudioDeviceInfo.TYPE_DOCK ||
            it.type == AudioDeviceInfo.TYPE_USB_DEVICE ||
            it.type == AudioDeviceInfo.TYPE_USB_ACCESSORY
        }
    }

    /**
     * Activate audio session for WebRTC (livestream without system call integration).
     * Sets up MODE_IN_COMMUNICATION which is required for WebRTC audio to work.
     * This is the Android equivalent of iOS's RTCAudioSession.audioSessionDidActivate().
     */
    fun activateForWebRTC() {
        val hasExternalDisplay = isExternalDisplayConnected()
        Log.d(TAG, "Activating audio session for WebRTC - hasExternalDisplay: $hasExternalDisplay")

        try {
            releaseAudioFocus()

            // Request audio focus for voice communication (WebRTC compatible)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
                    .setAudioAttributes(
                        AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
                            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                            .build()
                    )
                    .setAcceptsDelayedFocusGain(true)
                    .build()
                audioFocusRequest = focusRequest
                audioManager.requestAudioFocus(focusRequest)
            }

            // MODE_IN_COMMUNICATION is required for WebRTC audio
            audioManager.mode = AudioManager.MODE_IN_COMMUNICATION

            if (hasExternalDisplay) {
                // External display connected — do NOT force speaker.
                // Let Android route audio to Chromecast/HDMI.
                Log.d(TAG, "Audio session activated for WebRTC (external display)")
            } else {
                // Route to speaker
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    val speakerDevice = audioManager.availableCommunicationDevices.firstOrNull {
                        it.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER
                    }
                    speakerDevice?.let { audioManager.setCommunicationDevice(it) }
                }
                audioManager.isSpeakerphoneOn = true
                Log.d(TAG, "Audio session activated for WebRTC (speaker)")
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error activating audio session for WebRTC: ${e.message}")
        }
    }

    /**
     * Deactivate WebRTC audio session.
     * Call this when leaving a livestream to properly clean up.
     */
    fun deactivateWebRTC() {
        Log.d(TAG, "Deactivating WebRTC audio session")

        try {
            releaseAudioFocus()
            audioManager.mode = AudioManager.MODE_NORMAL
            audioManager.isSpeakerphoneOn = false
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                audioManager.clearCommunicationDevice()
            }
            Log.d(TAG, "WebRTC audio session deactivated")
        } catch (e: Exception) {
            Log.e(TAG, "Error deactivating WebRTC audio session: ${e.message}")
        }
    }

    /**
     * Release audio focus.
     */
    fun releaseAudioFocus() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            audioFocusRequest?.let { audioManager.abandonAudioFocusRequest(it) }
            audioFocusRequest = null
        }
    }

}
