package com.useasy.callsdk.demo

import android.Manifest
import android.app.Activity
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothHeadset
import android.bluetooth.BluetoothProfile
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.media.AudioManager
import android.os.Build
import android.os.Bundle
import android.os.PowerManager
import android.os.SystemClock
import android.util.DisplayMetrics
import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.Chronometer
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.useasy.callsdk.CallSDK
import com.useasy.callsdk.bean.CallDirection
import com.useasy.callsdk.bean.CallInfo
import com.useasy.callsdk.listener.CallStateListener
import com.useasy.callsdk.listener.MakeCallCallback
import com.useasy.callsdk.utils.AudioUtils

class CallActivity : BaseActivity() {

    companion object {
        private const val TAG = "CallActivity"
        private const val REQUEST_CODE_BLUETOOTH_CONNECT = 1001

        fun getLinearLayout(activity: Activity): LinearLayout {
            val layout = LinearLayout(activity)
            val params = LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT
            )
            layout.layoutParams = params
            layout.orientation = LinearLayout.HORIZONTAL
            return layout
        }
    }

    private lateinit var mActivityMain: RelativeLayout
    private lateinit var mTvPhone: TextView
    private lateinit var mTvCallDurtionPhone: TextView
    private lateinit var mIbtnHangUpAm: ImageButton
    private lateinit var mTvMuteAm: TextView
    private lateinit var mTvDailAm: TextView
    private lateinit var mTvSpeakerAm: TextView
    private lateinit var mLlDailLayout: LinearLayout
    private lateinit var mTvHiddenDail: TextView
    private lateinit var mLlOptionAm: LinearLayout
    private lateinit var mChronometer: Chronometer

    private var phoneNumber: String = ""
    private var userData: String? = null
    private var direction: CallDirection = CallDirection.APP
    private var wakeLock: PowerManager.WakeLock? = null
    private var hasChangedSpeaker: Boolean = false
    private var mHeadsetPlugReceiver: HeadsetPlugReceiver? = null
    private var bluetoothHeadset: BluetoothHeadset? = null
    private var bluetoothAdapter: BluetoothAdapter? = null

    private val dailNumber = arrayOf("1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#")

    // ═══════════════════════════════════════════
    //  通话状态监听器（统一处理两种通话场景）
    // ═══════════════════════════════════════════

    private val callStateListener = object : CallStateListener {
        override fun onCallAlerting(callInfo: CallInfo) {
            Log.d(TAG, "onCallAlerting: ${callInfo.callId}")
            mTvCallDurtionPhone.setText(R.string.callsdk_use_calling)
        }

        override fun onCallAnswered(callInfo: CallInfo) {
            Log.d(TAG, "onCallAnswered: ${callInfo.callId}")
            val currentRoute = getCurrentAudioRoute()
            AudioUtils.choiceAudioModel(this@CallActivity)
            updateSpeakerUI(currentRoute)

            mTvCallDurtionPhone.visibility = View.GONE
            mChronometer.visibility = View.VISIBLE
            mChronometer.base = SystemClock.elapsedRealtime()
            mChronometer.start()
        }

        override fun onCallReleased(callInfo: CallInfo, hangupType: Int) {
            Log.d(TAG, "onCallReleased: ${callInfo.callId}, hangupType=$hangupType")
            if (getSpeakerStatus()) {
                switchSpeaker()
            }
            stopTimeCountDown()
            finish()
        }

        override fun onCallFailed(callInfo: CallInfo, errorCode: Int, errorMsg: String) {
            Log.d(TAG, "onCallFailed: callId=${callInfo.callId}, errorCode=$errorCode, errorMsg=$errorMsg")
            Toast.makeText(this@CallActivity, errorMsg, Toast.LENGTH_LONG).show()
            if (getSpeakerStatus()) {
                switchSpeaker()
            }
            stopTimeCountDown()
            finish()
        }

        override fun onDtmfReceived(callInfo: CallInfo, dtmf: String) {
            Log.d(TAG, "onDtmfReceived: ${callInfo.callId}, dtmf: $dtmf")
        }
    }

    private val itemOnClickListener = View.OnClickListener { v ->
        when (v.id) {
            R.id.ibtn_hang_up_am -> {
                CallSDK.hangupCall()
                finish()
            }

            R.id.tv_mute_am -> {
                if (CallSDK.isMuteOn()) {
                    CallSDK.openMute(false)
                    setMuteTopDrawable(R.drawable.callsdk_mute_unenable)
                    mTvMuteAm.setTextColor(
                        ContextCompat.getColor(this, R.color.callsdk_color_e6e6e6)
                    )
                } else {
                    CallSDK.openMute(true)
                    setMuteTopDrawable(R.drawable.callsdk_mute_enable)
                    mTvMuteAm.setTextColor(ContextCompat.getColor(this, R.color.callsdk_white))
                }
            }

            R.id.tv_dail_am -> {
                showDailView()
            }

            R.id.tv_speaker_am -> {
                mTvCallDurtionPhone.post {
                    hasChangedSpeaker = true
                    switchSpeaker()
                }
            }

            R.id.tv_hidden_dail -> {
                mLlDailLayout.visibility = View.GONE
                mTvHiddenDail.visibility = View.GONE
                mLlOptionAm.visibility = View.VISIBLE
            }
        }
    }

    private val dialOnClickListener = View.OnClickListener { view ->
        val tag = view.tag as? String ?: return@OnClickListener
        val phone = mTvPhone.text.toString().trim()
        mTvPhone.text = phone + tag
        sendTMS(tag)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.callsdk_activity_call)
        resolveIntent()
        bindViews()
        initmHeadsetPlugReceiver()

        val powerManager = getSystemService(POWER_SERVICE) as PowerManager
        wakeLock =
            powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MicrophoneApp:WakeLock")
        wakeLock?.acquire()
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

        startCallService()

        // 注册通话状态监听器
        CallSDK.addCallStateListener(callStateListener)

        // 根据通话方向处理
        when (direction) {
            CallDirection.APP -> {
                // 主动外呼：发起通话
                val userDataJson = if (!userData.isNullOrEmpty()) {
                    try {
                        org.json.JSONObject(userData)
                    } catch (e: Exception) {
                        Log.w(TAG, "userData is not valid JSON, ignoring: $userData")
                        null
                    }
                } else null
                CallSDK.makeCall(phoneNumber, userDataJson, object : MakeCallCallback {
                    override fun onSuccess(callInfo: CallInfo) {
                        Log.d(TAG, "makeCall success: ${callInfo.callId}")
                    }

                    override fun onFailed(errorCode: Int, errorMsg: String) {
                        Log.d(TAG, "makeCall failed: errorCode=$errorCode, errorMsg=$errorMsg")
                        Toast.makeText(this@CallActivity, errorMsg, Toast.LENGTH_LONG).show()
                        finish()
                    }
                })
            }
        }
    }

    private fun resolveIntent() {
        phoneNumber = intent.getStringExtra("phoneNumber") ?: ""
        userData = intent.getStringExtra("userData")
        val directionStr = intent.getStringExtra("direction")
        direction = if (directionStr != null) {
            try {
                CallDirection.valueOf(directionStr)
            } catch (e: IllegalArgumentException) {
                CallDirection.APP
            }
        } else {
            CallDirection.APP
        }
    }

    private fun bindViews() {
        mActivityMain = findViewById(R.id.activity_main)
        mTvPhone = findViewById(R.id.tv_contact_phone)
        mTvCallDurtionPhone = findViewById(R.id.tv_call_durtion_phone)
        mIbtnHangUpAm = findViewById(R.id.ibtn_hang_up_am)
        mTvMuteAm = findViewById(R.id.tv_mute_am)
        mTvDailAm = findViewById(R.id.tv_dail_am)
        mTvSpeakerAm = findViewById(R.id.tv_speaker_am)
        mLlDailLayout = findViewById(R.id.ll_dail_layout)
        mTvHiddenDail = findViewById(R.id.tv_hidden_dail)
        mLlOptionAm = findViewById(R.id.ll_option_am)
        mChronometer = findViewById(R.id.chronometer_am)

        mIbtnHangUpAm.setOnClickListener(itemOnClickListener)
        mTvMuteAm.setOnClickListener(itemOnClickListener)
        mTvDailAm.setOnClickListener(itemOnClickListener)
        mTvSpeakerAm.setOnClickListener(itemOnClickListener)
        mTvHiddenDail.setOnClickListener(itemOnClickListener)

        // 显示号码，服务端通话可能没有号码
        mTvPhone.text = when {
            phoneNumber.isNotEmpty() -> phoneNumber
            else -> "服务端通话"
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        // 移除通话状态监听器
        CallSDK.removeCallStateListener(callStateListener)
        stopCallService()
        unregisterHeadsetPlugReceiver()
        releaseBluetoothProfile()
        wakeLock?.release()
        window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    }

    private fun releaseBluetoothProfile() {
        bluetoothHeadset?.let {
            try {
                bluetoothAdapter?.closeProfileProxy(BluetoothProfile.HEADSET, it)
                Log.d(TAG, "BluetoothHeadset profile released")
            } catch (e: Exception) {
                Log.e(TAG, "释放蓝牙 Profile 失败: ${e.message}")
            }
            bluetoothHeadset = null
        }
    }

    private fun initmHeadsetPlugReceiver() {
        mHeadsetPlugReceiver = HeadsetPlugReceiver(this, object : AudioRouteChangeListener {
            override fun onAudioRouteChanged(route: AudioRoute) {
                updateSpeakerUI(route)
            }
        })
        val intentFilter = IntentFilter().apply {
            addAction(Intent.ACTION_HEADSET_PLUG)
            addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)
            addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
        }
        registerReceiver(mHeadsetPlugReceiver, intentFilter)
        Log.d(TAG, "HeadsetPlugReceiver registered")

        initBluetoothProfile()
    }

    private fun getCurrentAudioRoute(): AudioRoute {
        return when {
            AudioUtils.isWiredHeadsetOn(this) -> AudioRoute.RECEIVER
            AudioUtils.isBluetoothA2dpOn(this) -> AudioRoute.BLUETOOTH
            else -> AudioRoute.SPEAKER
        }
    }

    private fun updateSpeakerUI(route: AudioRoute) {
        when (route) {
            AudioRoute.SPEAKER -> {
                setSpeakerTopDrawable(R.drawable.callsdk_speaker_enable)
                mTvSpeakerAm.setTextColor(ContextCompat.getColor(this, R.color.callsdk_white))
            }
            AudioRoute.RECEIVER -> {
                setSpeakerTopDrawable(R.drawable.callsdk_speaker_unenable)
                mTvSpeakerAm.setTextColor(ContextCompat.getColor(this, R.color.callsdk_color_e6e6e6))
            }
            AudioRoute.BLUETOOTH -> {
                setSpeakerTopDrawable(R.drawable.callsdk_speaker_unenable)
                mTvSpeakerAm.setTextColor(ContextCompat.getColor(this, R.color.callsdk_color_e6e6e6))
            }
        }
        Log.d(TAG, "扬声器UI已更新: $route")
    }

    private fun hasBluetoothConnectPermission(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_CONNECT
            ) == PackageManager.PERMISSION_GRANTED
        } else {
            true
        }
    }

    private fun requestBluetoothConnectPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.BLUETOOTH_CONNECT),
                REQUEST_CODE_BLUETOOTH_CONNECT
            )
        }
    }

    private fun initBluetoothProfile() {
        try {
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
            bluetoothAdapter?.getProfileProxy(
                this,
                object : BluetoothProfile.ServiceListener {
                    override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
                        if (profile == BluetoothProfile.HEADSET) {
                            bluetoothHeadset = proxy as BluetoothHeadset
                            Log.d(TAG, "BluetoothHeadset profile connected")

                            if (hasBluetoothConnectPermission()) {
                                checkBluetoothDevices()
                            } else {
                                Log.w(TAG, "缺少 BLUETOOTH_CONNECT 权限，无法检查蓝牙设备")
                                requestBluetoothConnectPermission()
                            }
                        }
                    }

                    override fun onServiceDisconnected(profile: Int) {
                        if (profile == BluetoothProfile.HEADSET) {
                            Log.d(TAG, "BluetoothHeadset profile disconnected")
                            bluetoothHeadset = null
                        }
                    }
                },
                BluetoothProfile.HEADSET
            )
        } catch (e: Exception) {
            Log.e(TAG, "初始化蓝牙 Profile 失败: ${e.message}")
        }
    }

    private fun checkBluetoothDevices() {
        try {
            val connectedDevices = bluetoothHeadset?.connectedDevices
            if (connectedDevices != null && connectedDevices.isNotEmpty()) {
                Log.d(TAG, "蓝牙耳机已连接，设备数量: ${connectedDevices.size}")
                AudioUtils.changeToHeadset(this)
                runOnUiThread {
                    updateSpeakerUI(AudioRoute.BLUETOOTH)
                }
            }
        } catch (e: SecurityException) {
            Log.e(TAG, "检查蓝牙设备失败，缺少权限: ${e.message}")
        } catch (e: Exception) {
            Log.e(TAG, "检查蓝牙设备失败: ${e.message}")
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        when (requestCode) {
            REQUEST_CODE_BLUETOOTH_CONNECT -> {
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "BLUETOOTH_CONNECT 权限已授予")
                    checkBluetoothDevices()
                } else {
                    Log.w(TAG, "BLUETOOTH_CONNECT 权限被拒绝")
                }
            }
        }
    }

    private fun unregisterHeadsetPlugReceiver() {
        mHeadsetPlugReceiver?.let {
            try {
                unregisterReceiver(it)
                Log.d(TAG, "HeadsetPlugReceiver unregistered")
            } catch (e: Exception) {
                Log.e(TAG, "Failed to unregister HeadsetPlugReceiver: ${e.message}")
            }
            mHeadsetPlugReceiver = null
        }
    }

    private fun startCallService() {
        val intent = Intent(this, CallService::class.java).apply {
            action = CallService.ACTION_START_CALL
            putExtra(CallService.EXTRA_PHONE_NUMBER, phoneNumber)
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(intent)
        } else {
            startService(intent)
        }
        Log.d(TAG, "CallService started")
    }

    private fun stopCallService() {
        val intent = Intent(this, CallService::class.java).apply {
            action = CallService.ACTION_STOP_CALL
        }
        stopService(intent)
        Log.d(TAG, "CallService stopped")
    }

    private fun setSpeakerTopDrawable(resId: Int) {
        val topDrawable = ContextCompat.getDrawable(this, resId)
        topDrawable?.setBounds(0, 0, topDrawable.minimumWidth, topDrawable.minimumHeight)
        mTvSpeakerAm.setCompoundDrawables(null, topDrawable, null, null)
    }

    private fun setMuteTopDrawable(resId: Int) {
        val topDrawable = ContextCompat.getDrawable(this, resId)
        topDrawable?.setBounds(0, 0, topDrawable.minimumWidth, topDrawable.minimumHeight)
        mTvMuteAm.setCompoundDrawables(null, topDrawable, null, null)
    }

    private fun stopTimeCountDown() {
        if (mChronometer.visibility == View.VISIBLE) {
            mChronometer.stop()
        }
    }

    private fun showDailView() {
        mLlDailLayout.visibility = View.VISIBLE
        mTvHiddenDail.visibility = View.VISIBLE
        mLlOptionAm.visibility = View.GONE
        if (mLlDailLayout.childCount > 2) {
            return
        }
        var layout: LinearLayout? = null
        for (i in dailNumber.indices) {
            if (i % 3 == 0) {
                layout = getLinearLayout(this)
                mLlDailLayout.addView(layout)
            }
            val textView = getItemView(dailNumber[i])
            layout?.addView(textView)
        }
    }

    private fun getItemView(s: String): TextView {
        val textView = TextView(this)
        val screenWidth = getDisplay(this).widthPixels
        val params = LinearLayout.LayoutParams(screenWidth / 5, screenWidth / 5)
        params.setMargins(screenWidth / 30, screenWidth / 50, screenWidth / 30, 0)
        textView.layoutParams = params
        textView.gravity = Gravity.CENTER
        textView.textSize = (screenWidth / 40).toFloat()
        textView.text = s
        textView.setBackgroundResource(R.drawable.callsdk_bg_circle_white)
        textView.setTextColor(ContextCompat.getColor(this, R.color.callsdk_maincolor))
        textView.tag = s
        textView.setOnClickListener(dialOnClickListener)
        return textView
    }

    private fun sendTMS(tag: String) {
        CallSDK.sendDTMF(tag[0].toString())
    }

    @Synchronized
    fun getSpeakerStatus(): Boolean {
        return CallSDK.isLoudSpeakerOn()
    }

    @Synchronized
    fun switchSpeaker() {
        switchSpeaker(!getSpeakerStatus())
    }

    @Synchronized
    fun switchSpeaker(mSpeaker: Boolean) {
        Log.d(TAG, "switchSpeaker speaker: $mSpeaker")
        CallSDK.openLoudSpeaker(mSpeaker)
        if (!mSpeaker) {
            setSpeakerTopDrawable(R.drawable.callsdk_speaker_unenable)
            mTvSpeakerAm.setTextColor(ContextCompat.getColor(this, R.color.callsdk_color_e6e6e6))
        } else {
            setSpeakerTopDrawable(R.drawable.callsdk_speaker_enable)
            mTvSpeakerAm.setTextColor(ContextCompat.getColor(this, R.color.callsdk_white))
        }
    }

    fun getDisplay(activity: Activity): DisplayMetrics {
        val outMetrics = DisplayMetrics()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            val display = activity.display
            display?.getRealMetrics(outMetrics)
        } else {
            @Suppress("DEPRECATION")
            activity.windowManager.defaultDisplay.getMetrics(outMetrics)
        }
        return outMetrics
    }
}
