package com.ydl.audioim

import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Paint
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.media.AudioManager
import android.media.MediaPlayer
import android.net.Uri
import android.os.*
import android.provider.Settings
import android.text.TextUtils
import android.view.View
import android.view.WindowManager
import android.view.animation.AccelerateInterpolator
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.google.gson.Gson
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.XXPermissions
import com.ydl.audioim.bean.AgoraInvitationBean
import com.ydl.audioim.bean.AgoraLogInfoBean
import com.ydl.audioim.contract.IAudioHomeActivityContract
import com.ydl.audioim.http.AudioApiRequestUtil
import com.ydl.audioim.http.AudioNetAPi
import com.ydl.audioim.http.LeaveChannelReason
import com.ydl.audioim.http.RtcEvent
import com.ydl.audioim.http.command.ConnectCommand
import com.ydl.audioim.http.command.ConnectExceptionCommand
import com.ydl.audioim.http.command.NoticePushCommand
import com.ydl.audioim.http.command.PayLoad
import com.ydl.audioim.listener.IntentConstants
import com.ydl.audioim.player.AudioPlayer
import com.ydl.audioim.presenter.AudioHomePresenterImpl
import com.ydl.audioim.router.AudioImIn
import com.ydl.audioim.utils.AudioLogUtils
import com.ydl.audioim.utils.DateUtils
import com.ydl.audioim.utils.onConfideEvent
import com.ydl.audioim.widget.AxbConfirmDialog
import com.ydl.audioim.widget.ZDialog
import com.ydl.devicesidlib.DeviceIDHelper
import com.ydl.webview.H5Params
import com.ydl.webview.NewH5Activity
import com.ydl.webview.RefreshWebEvent
import com.ydl.ydl_av.chat.bean.AudioMessageBean
import com.ydl.ydl_av.voice.listener.IYDLVoiceEventHandler
import com.ydl.ydl_av.voice.manager.YDLVoiceManager
import com.ydl.ydl_image.config.SimpleImageOpConfiger
import com.ydl.ydl_image.manager.YDLImageCacheManager
import com.ydl.ydlcommon.app.Apm
import com.ydl.ydlcommon.base.BaseMvpActivity
import com.ydl.ydlcommon.modular.ModularServiceManager
import com.ydl.ydlcommon.modular.findRouteService
import com.ydl.ydlcommon.router.YdlCommonRouterManager
import com.ydl.ydlcommon.utils.LogUtil
import com.ydl.ydlcommon.utils.Utils
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils
import com.ydl.ydlcommon.utils.log.AliYunLogConfig
import com.ydl.ydlcommon.utils.log.AliYunRichLogsHelper
import com.ydl.ydlcommon.utils.log.LogHelper
import com.ydl.ydlcommon.utils.log.XLog
import com.ydl.ydlcommon.utils.remind.ToastHelper
import com.ydl.ydlnet.YDLHttpUtils
import com.yidianling.common.tools.ToastUtil
import com.yidianling.im.api.bean.IMRegisterObserverCustomNotificationCallBack
import com.yidianling.im.api.service.IImService
import com.yidianling.user.api.service.IUserService
import de.greenrobot.event.EventBus
import io.agora.rtc.Constants
import io.agora.rtc.IRtcEngineEventHandler
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.audioim_activity_audio_home.*
import java.util.*
import java.util.concurrent.TimeUnit

/**
 * @author jiucheng
 * @描述: 倾诉声网通话页面（拨打电话界面）
 * @Copyright Copyright (c) 2018
 * @Company 壹点灵
 * @date 2018/10/30
 */
@Route(path = "/av/AudioHomeActivity")
class AudioHomeActivity :
    BaseMvpActivity<IAudioHomeActivityContract.View, IAudioHomeActivityContract.Presenter>(),
    IAudioHomeActivityContract.View, SensorEventListener {

    /**
     * 专家头像地址
     */
    private var expertHeadUrl: String? = null

    /**
     * 专家姓名
     */
    private var expertName: String? = null

    /**
     * 专家文案
     */
    private var expertTips: String? = null

    /**
     * 声网点对点聊天房间id
     */
    private var channelId: String? = null

    /**
     * 通话开始时间（接通）
     */
    private var callStartTime: Long? = null

    /**
     * 倾诉剩余时长（时长单位s，eg：剩余2min15s，返回135）
     */
    private var remainTime: String? = null

    /**
     *聆听者id（不是聆听者的uid）
     */
    private var listenId: String? = null

    /**
     * token
     */
    private var token: String? = null

    /**
     * commentUrl 评价页URL
     */
    private var commentUrl: String? = null

    /**
     * callId
     */
    private var callId: String? = null

    /**
     * relation_id
     */
    private var relationId: String? = null

    /**
     * listenerUid专家uid
     */
    private var listenerUid: String? = null

    /**
     * 倾述总时长
     */
    private var totalDuration: Int? = 0

    /**
     * 本地记录的当前剩余时间
     */
    private var localRemainTime: Int? = 0

    /**
     * 挂断电话需要等待时间
     */
    private var onlineCallTime: Long? = 0

    /**
     * 跳转传统电话需要等待时间
     */
    private var traditionCallTime: Long? = 0

    /**
     * 50s自动挂断倒计时
     */
    private var waitDisposable: Disposable? = null

    /**
     * 45s倒计时
     */
    private var disposable: Disposable? = null

    /**
     * 本次倾述倒计时
     */
    private var totalDisposable: Disposable? = null

    /**
     * 是否连接成功
     */
    private var isConnectSuccess: Boolean = false

    //电源管理对象
    private var localPowerManager: PowerManager? = null

    //电源锁
    private var localWakeLock: PowerManager.WakeLock? = null
    private var sensorManager: SensorManager? = null
    private var sendDoctocrMsg: String? = null
    private var axbPhone: String? = null

    //是否跳转到拨号页面
    private var isJumpDail: Boolean = false
    private var isShowAXB: Boolean = true
    private var mPlayer: AudioPlayer? = null
    private var vibrator: Vibrator? = null
    private var handler: Handler? = null
    private var phoneHandler: Handler? = Handler(Looper.getMainLooper())

    //声网
    private var voiceManage: YDLVoiceManager? = null


    //频道管理器
//    private var channelManager: ChannelManager? = null

    private var isLeavelChannel: Boolean = false
    private var hasUpLoadLog = false

    private var callStatus: Int = -1

    /**
     * dialStatus 专家通话状态。
     */
    private var dialStatus: String? = null

    private var mStorageDialog: ZDialog? = null

    private var mHangUpTimeTraditionalDialog: ZDialog? = null

    private var mHangUpTimeOnlineDialog: ZDialog? = null

    private var canHangUp: Boolean = false

    private var canChangeRoute: Boolean = false

    private var hasHandleRefused = false

    private var hasJoinChannel = false

    private val tvNetDelay: TextView by lazy { findViewById(R.id.tvDelay) }
    private val tvNetDown: TextView by lazy { findViewById(R.id.tvDown) }
    private val tvNetUp: TextView by lazy { findViewById(R.id.tvUp) }
    private val ivNetQuality: ImageView by lazy { findViewById(R.id.ivQuality) }
    private val tvNetQuality: TextView by lazy { findViewById(R.id.tvQuality) }
    private val layoutQualityGroup: View by lazy { findViewById(R.id.layoutQualityGroup) }

    private val notificationCallback = object : IMRegisterObserverCustomNotificationCallBack {
        override fun onObserverCustomNotification(fromUid: String, toUid: String, content: String) {
            if (fromUid == listenerUid) {
                try {
                    val bean = Gson().fromJson(content, AgoraInvitationBean::class.java)
                    when (bean.callType) {
                        "2" -> {//接受
                            runOnUiThread {
                                joinChannel()
                            }
                        }
                        "4" -> {//拒绝
                            onCallRefused()
                        }
                    }
                } catch (throwable: Throwable) {
                    LogUtil.e(throwable.message)
                }
            }
        }
    }

    fun onCallRefused() {
        runOnUiThread {
            if (hasHandleRefused) return@runOnUiThread
            hasHandleRefused = true
            YDLavManager.instances.callEndStatusUpdate(channelId, 2, "被叫拒绝")
            ToastUtil.toastShort("对方已挂断")
            writeAgoraLog("被叫（专家）拒绝了通话邀请")
            //通话结束或挂断时，上传日志文件
            uploadLog()
            leaveChannel(1)
            uploadExceptionStatus("对方已拒绝", 2)
        }
    }

    /**
     * 声网事件回调 （SDK 通过指定的事件通知应用程序 SDK 的运行事件，如: 加入或离开频道，新用户加入频道等）
     */
    private val mRtcEventHandler = object : IYDLVoiceEventHandler() {

        override fun onUserMuteAudio(uid: Int, muted: Boolean) {
        }

        override fun onWarning(warn: Int) {
            super.onWarning(warn)
            uploadException("mRtcEventHandler-onWarning:warnCode--%${warn}", callback = null)
            LogUtil.e("[agora]发生警告回调$warn")
            writeAgoraLog("声网警告回调($warn)")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "声网警告回调($warn)   channelId:${channelId}")
            //103：没有可用的频道资源。可能是因为服务端没法分配频道资源
            //104：查找频道超时。在加入频道时 SDK 先要查找指定的频道，出现该警告一般是因为网络太差，连接不到服务器
            //105：查找频道请求被服务器拒绝。服务器可能没有办法处理这个请求或请求是非法的
            //106：打开频道超时。查找到指定频道后，SDK 接着打开该频道，超时一般是因为网络太差，连接不到服务器
            //107：打开频道请求被服务器拒绝。服务器可能没有办法处理该请求或该请求是非法的
            // 声网发出警告错误码，不应该直接离开房间

        }

        /**
         * https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html
         * */
        override fun onError(err: Int) {
            super.onError(err)
            uploadException("mRtcEventHandler-onError:errorCode--%${err}", callback = null)
            writeAgoraLog("声网错误回调errorCode--%${err}")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "声网错误回调errorCode--%${err}    channelId:${channelId}")
            //3：SDK 初始化失败。Agora 建议尝试以下处理方法
            //7：SDK 尚未初始化，就调用其 API。请确认在调用 API 之前已创建 RtcEngine 对象并完成初始化
            //9：没有操作权限。请检查用户是否授予 app 音视频设备使用权限。
            //10：API 调用超时。有些 API 调用需要 SDK 返回结果，如果 SDK 处理时间过长，超过 10 秒没有返回，会出现此错误
            //17：加入频道被拒绝。一般有以下原因：
            //用户已进入频道，再次调用加入频道的 API，例如 joinChannel，会返回此错误。停止调用该方法即可。
            //用户在做 Echo 测试时尝试加入频道。等待 Echo test 结束后再加入频道即可。
            //101：不是有效的 APP ID。请更换有效的 APP ID 重新加入频道
            //102：不是有效的 频道名。请更换有效的频道名重新加入频道
            //109：当前使用的 Token 过期，不再有效
            //110：生成的 Token 无效
            //123：此用户被服务器禁止
            LogUtil.e("[agora]发生错误回调$err")
            if (err == 0 || err == 18) {
                return
            }
            Apm.reportEvent("agora_android", "occur_error", "$err")
            AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.errorOccurred), errorCode = err)
            channelId?.let { YDLavManager.instances.callEndStatusUpdate(it, 60, "频道错误回调$err") }
        }

        override fun onApiCallExecuted(error: Int, api: String?, result: String?) {
            super.onApiCallExecuted(error, api, result)
//            LogUtil.e("[agora]$api 已执行回调 $result")
            //注销原因，产生大量无效数据，会被频繁调用
//            AliYunRichLogsHelper.getInstance()
//                .sendLog(AliYunLogConfig.AGORA, "$api 已执行回调 $result")
        }

        override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
            super.onJoinChannelSuccess(channel, uid, elapsed)
            onMeJoined()
            callEventSave("20", "$uid 用户声网加入频道成功:channel=$channel")
            AudioApiRequestUtil.reportCallEvent(channel, RtcEvent(RtcEvent.Event.joinSuccess))

            LogUtil.e("[agora]$uid 用户声网加入频道成功:channel=$channel")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "$uid 用户声网加入频道成功:channel=$channel")
            //更新ui
//            onJoinChannelSuccess()

            //更新：现在专家先加入频道，所以不会有等待的过程，
            runOnUiThread {
                writeAgoraLog("主叫加入频道成功")
                //自己加入频道成功
                connectSuccess()
            }

        }

        override fun onRejoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
            super.onRejoinChannelSuccess(channel, uid, elapsed)
            callEventSave("70", "$uid 用户声网加入频道成功:channel=$channel")

            LogUtil.e("[agora]$uid 用户声网重新加入频道成功:channel=$channel")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "$uid 用户声网重新加入频道成功:channel=$channel")
            runOnUiThread {
                //自己加入频道成功
                if (!isConnectSuccess) {
                    writeAgoraLog("主叫重新加入频道成功")
                    connectSuccess()
                }
            }
        }


        override fun onRtcStats(stats: IRtcEngineEventHandler.RtcStats?) {
            super.onRtcStats(stats)
            writeAgoraLog("声网onRtcStats：users:${stats?.users}")
//            AliYunRichLogsHelper.getInstance()
//                .sendRichLog(AliYunLogConfig.AGORA, "声网onRtcStats：users:${stats?.users}   channelId:${channelId}")
            // 不需要移动端做离开房间逻辑，服务端会判断进行踢人逻辑
            //因为用户端直接加入了频道，防止该回调执行时，专家还未加入频道，因此在连接成功之后，才进行频道人数判断
//            if (isConnectSuccess && null != stats?.users && stats.users == 1) {
//                writeAgoraLog("通话结束：用户加入了频道，但频道内只有一个人")
//                com.yidianling.common.tools.ToastUtil.toastShort("专家已挂断")
//                //通话结束或挂断时，上传日志文件
//                uploadLog()
//                leaveChannel()
//            }
        }

        override fun onFirstLocalAudioFrame(elapsed: Int) {
            AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.localFirstFrame))
        }

        override fun onFirstRemoteAudioFrame(uid: Int, elapsed: Int) {
            AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.remoteFirstFrame))
        }

        /**
         * https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler.html#a31b2974a574ec45e62bb768e17d1f49e
         * */
        override fun onConnectionStateChanged(state: Int, reason: Int) {
            super.onConnectionStateChanged(state, reason)
            // 3 网络连接被服务器中止  该情况现在是因为后端踢人逻辑
            Apm.reportEvent("agora_android", "rtc_connection_failure", "$state,$reason")
            AudioApiRequestUtil.reportCallEvent(
                channelId,
                RtcEvent(RtcEvent.Event.connectionChanged),
                errorCode = state, errorReason = reason.toString()
            )
            if (reason == 3) {//网络连接被服务器禁止
                callEventSave("50", "通话结束：网络连接被服务器中止  该情况现在是因为后端踢人逻辑,原因（${reason}")
                writeAgoraLog("通话结束：网络连接被服务器中止  该情况现在是因为后端踢人逻辑,原因（${reason}）")
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(
                        AliYunLogConfig.AGORA,
                        "通话结束：网络连接被服务器中止  该情况现在是因为后端踢人逻辑,原因（${reason}）   channelId:${channelId}"
                    )
//                com.yidianling.common.tools.ToastUtil.toastShort("专家已挂断")
                //通话结束或挂断时，上传日志文件
                uploadLog()
                leaveChannel(10)
            }
        }

        override fun onLeaveChannel(stats: IRtcEngineEventHandler.RtcStats?) {
            super.onLeaveChannel(stats)
            callEventSave("51", "离开频道回调stats=${stats}")

            LogUtil.e("[agora]离开频道回调")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "离开频道回调  channelId:${channelId}")
            //通话结束或挂断时，上传日志文件
            uploadLog()
        }


        override fun onUserJoined(uid: Int, elapsed: Int) {
            super.onUserJoined(uid, elapsed)
            callEventSave("20", "${uid}加入频道回调")
            LogUtil.e("[agora]远端用户/主播加入频道回调")
            onPeerJoined()
            AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.remoteJoin))
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "远端用户/主播加入频道回调   channelId:${channelId}")
        }

        override fun onUserOffline(uid: Int, reason: Int) {
            super.onUserOffline(uid, reason)
            callEventSave("51", "uid:${uid}离开频道回调   elapsed:${reason}")

            LogUtil.e("[agora]远端用户$uid 离开频道回调")
            writeAgoraLog("接通后通话结束：对方已挂断")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "接通后通话结束：对方已挂断  channelId:${channelId}")
            //通话结束或挂断时，上传日志文件
            uploadLog()
            AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.remoteLeave), retCode = reason)
            showToast("专家已挂断")
            //UserOffLine之后，销毁界面，解决，userOffline有回调之后，onConnectionStateChanged(服务端踢人方法没有调)，导致记录时长异常。
            if (reason == Constants.USER_OFFLINE_DROPPED) {
                YDLavManager.instances.callEndStatusUpdate(channelId, 3, "对方超时掉线")
            }
            leaveChannel(if (reason == Constants.USER_OFFLINE_DROPPED) 3 else 4)

            if (totalDisposable != null) {
                totalDisposable?.dispose()
            }
            handler?.postDelayed({
                //另一方离开频道
                updateExpertStatus(false, 1)
            }, 500)


        }


        //本地音频状态变化
        override fun onLocalAudioStateChanged(localVideoState: Int, error: Int) {
            super.onLocalAudioStateChanged(localVideoState, error)
            writeAgoraLog("本地音频回调$error")
        }

        override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {
            super.onNetworkQuality(uid, txQuality, rxQuality)
            LogUtil.e("onNetworkQuality:-------uid=$uid,txQuality=$txQuality,rxQuality=$rxQuality")
            runOnUiThread {
                var status = -1
                var netStatus = when (uid) {
                    0 -> {
                        if (txQuality in 1..2 && rxQuality in 1..2) {
                            ""
                        } else if (txQuality >= 5 || rxQuality >= 5) {
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(AliYunLogConfig.AGORA, "您的网络已断开  channelId:${channelId}")
                            "您的网络已断开"
                        } else {
                            status = if (txQuality >= 4 || rxQuality >= 4) {
                                0
                            } else {
                                1
                            }
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(AliYunLogConfig.AGORA, "您的网络状况不佳  channelId:${channelId}")
                            "您的网络状况不佳"
                        }
                    }
                    else -> {
                        if (txQuality in 1..2 && rxQuality in 1..2) {
                            ""
                        } else if (txQuality >= 5 || rxQuality >= 5) {
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(AliYunLogConfig.AGORA, "对方的网络已断开  channelId:${channelId}")
                            "对方的网络已断开"
                        } else {
                            status = if (txQuality >= 4 || rxQuality >= 4) {
                                0
                            } else {
                                1
                            }
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(AliYunLogConfig.AGORA, "对方的网络状况不佳  channelId:${channelId}")
                            "对方的网络状况不佳"
                        }
                    }
                }
                showNetStatus(netStatus, status)
            }
        }
    }
//

    override fun createPresenter(): IAudioHomeActivityContract.Presenter {
        return AudioHomePresenterImpl()
    }

    override fun layoutResId(): Int {
        return R.layout.audioim_activity_audio_home
    }

    @SuppressLint("CheckResult")
    override fun initDataAndEvent() {
        //状态栏颜色
        setWindowStatusBarColor()
        //初始化传感器
        initSensorManager()
        //页面传递数据初始化
        initIntentData()
        callEventSave("20", "用户进入通话页面")

        writeAgoraLog("通话页面打开的时候，RTM登录状态码：${YDLavManager.sdkStatus}")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(
                AliYunLogConfig.RTM,
                "通话页面打开的时候，RTM登录状态码：${YDLavManager.sdkStatus}   channelId:${channelId}"
            )
        if (YDLavManager.sdkStatus != Constants.CONNECTION_STATE_CONNECTED) {
            //再次登录声网，确保声网登录状态
            reLoginRTM()
        }
        //view初始化
        initView()
        //点击事件
        setClickEvent()
        //权限申请
        requestPermission()
        findRouteService(IImService::class.java).registerObserveCustomNotification(notificationCallback)

        Single.create<Int> {
            val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
            val callMax = audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL)
            val call = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL)
            val callPercent = (100F * call / callMax).toInt()
            it.onSuccess(callPercent)
        }
            .subscribeOn(Schedulers.io())
            .subscribe(Consumer {
                val req = hashMapOf(
                    "deviceId" to DeviceIDHelper.getInstance().deviceId,
                    "voice" to it
                )
                YDLHttpUtils.obtainApi(AudioNetAPi::class.java).report(req).subscribe()
            })

        ActionCountUtils.record("call_phone_page", "call_phone_page_visit", listenerUid ?: "0", "1")
    }


    private fun setWindowStatusBarColor() {
        val decorView = window.decorView
        val option = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
        decorView.systemUiVisibility = option
        window.statusBarColor = Color.TRANSPARENT
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            window.attributes?.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
        }
    }

    @SuppressLint("InvalidWakeLockTag")
    private fun initSensorManager() {
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager?

        localPowerManager = getSystemService(POWER_SERVICE) as PowerManager?
        localWakeLock = localPowerManager?.newWakeLock(
            PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
            "yidianling"
        )

        // 获取电源管理器对象
        val screenOn = localPowerManager?.isScreenOn
        if (screenOn == false) {
            // 获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag
            val wl = localPowerManager?.newWakeLock(
                PowerManager.ACQUIRE_CAUSES_WAKEUP or
                        PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright"
            )
            wl?.acquire(10000) // 点亮屏幕
            wl?.release() // 释放
        }

    }

    private fun initIntentData() {
        expertHeadUrl = intent.getStringExtra(IntentConstants.INTENT_EXPERT_HEAD_URL)
        expertName = intent.getStringExtra(IntentConstants.INTENT_EXPERT_NAME)
        expertTips = intent.getStringExtra(IntentConstants.INTENT_EXPERT_TIPS)
        totalDuration = intent.getStringExtra(IntentConstants.INTENT_TOTAL_DURATION).toInt()
        channelId = intent.getStringExtra(IntentConstants.INTENT_ROOM_ID)
        remainTime = intent.getStringExtra(IntentConstants.INTENT_REMAIN_TIME)
        callId = intent.getStringExtra(IntentConstants.INTENT_CALL_ID)
        relationId = intent.getStringExtra(IntentConstants.INTENT_RELATION_ID)
        token = intent.getStringExtra(IntentConstants.INTENT_TOKEN)
        listenerUid = intent.getStringExtra(IntentConstants.INTENT_LISTENER_UID)
        listenId = intent.getStringExtra(IntentConstants.INTENT_LISTEN_ID)
        commentUrl = intent.getStringExtra(IntentConstants.INTENT_COMMENT_URL)
        dialStatus = intent.getStringExtra(IntentConstants.INTENT_DIALSTATUS)
        writeAgoraLog("专家的通话状态dialStatus：$dialStatus", false)
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "专家的通话状态dialStatus：$dialStatus   channelId:${channelId}")
        isShowAXB = intent.getBooleanExtra(IntentConstants.INTENT_ISSHOWAXB, true)

        val logBean = AgoraLogInfoBean(
            expertHeadUrl,
            expertName,
            channelId,
            remainTime,
            listenerUid,
            totalDuration,
            callId,
            listenId
        )
        val content = Gson().toJson(logBean)
        writeAgoraLog("主叫方发送的邀请通话消息内容：$content", true)
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "主叫方发送的邀请通话消息内容：$content    channelId:${channelId}")
        localRemainTime = remainTime?.toInt() ?: 1500
        handler = Handler()

        vibrator = getSystemService(Service.VIBRATOR_SERVICE) as Vibrator?

        var count = 0
        phoneHandler?.postDelayed(object : Runnable {
            override fun run() {
                if (count % 2 == 0) {
                    tv_tips.text = "正在发送倾诉请求…"
                } else {
                    tv_tips.text = "正在等待聆听者接受邀请…"
                }
                count++
                phoneHandler?.postDelayed({ this.run() }, 3000)
            }
        }, 3000)

    }

    private fun reLoginRTM() {
        callEventSave("80", "RMT状态:${YDLavManager.sdkStatus},重新登录RMT")

        writeAgoraLog("RMT状态:${YDLavManager.sdkStatus},重新登录RMT")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.RTM, "RMT状态:${YDLavManager.sdkStatus},重新登录RMTt   channelId:${channelId}")
        val uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
        YDLavManager.instances.login(uid) { _isSuccess, _msg ->
//            writeAgoraLog("拨打电话界面打开RTM重新登录，uid=${uid}")
            val result =
                if (_isSuccess) "拨打电话界面打开RMT重新登录成功，uid=${uid}" else "拨打电话界面打开RMT登录失败:$_msg，uid=${uid}"
            writeAgoraLog(result)
        }
    }

    private fun initView() {
        callEventSave("20", "通话页面打开")
        writeAgoraLog("用户拨打电话界面开启")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "用户拨打电话界面开启   channelId:${channelId}")
        //水波纹view初始化
        wave_view.setDuration(6000)
        wave_view.setStyle(Paint.Style.STROKE)
        wave_view.setSpeed(1000)
        wave_view.setColor(Color.WHITE)
        wave_view.setInitialRadius(140f)
        wave_view.setInterpolator(AccelerateInterpolator(1.2f))
        //挂断按钮默认不可点击

        //设置默认关闭扬声器
        iv_hands_free.isSelected = false

        tv_name.text = expertName
//        tv_tips.text = expertTips
        val time = totalDuration?.minus(remainTime!!.toInt())
        tv_remain_time.text = DateUtils.formatTime((time).toString())
        val timeTotal= totalDuration?.div(60);
        tv_totalDuration.text="（满${timeTotal}分钟自动挂断,限24小时内拨打）"
        if (!TextUtils.isEmpty(expertHeadUrl)) {
            val option = SimpleImageOpConfiger()
            option.errorPic = R.drawable.audioim_head_place_hold_pic
            option.loadingPic = R.drawable.audioim_head_place_hold_pic
            option.transform = 0
            YDLImageCacheManager.showImage(this, expertHeadUrl, iv_head, option)
        }

        if (!isShowAXB) {
            ll_changeRoute.visibility = View.GONE
            tv_change_time_counter.visibility = View.GONE
        }
    }

    private fun setClickEvent() {
        //跳转客服小壹
        jump_kefu.setOnClickListener {
            if (!AudioImIn.getUserService().loginByOneKeyLogin(this@AudioHomeActivity,true)) {
                return@setOnClickListener
            }
            val imService = ARouter.getInstance().navigation(IImService::class.java)
            imService?.startKefuChat(this, "", 0, 0)
        }
        //静音开启
        rl_mute_on_off.setOnClickListener {
            ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "2")
            if (iv_mute_on_off.isSelected) {
                iv_mute_on_off.isSelected = false
                iv_mute_on_off.setImageResource(R.drawable.audiohome_muteoff)
                audio_mute_text.text = "麦克风已关"
                voiceManage?.getVoiceApi()?.enableLocalAudio(false)
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：麦克风已关   channelId:${channelId}")
            } else {
                iv_mute_on_off.isSelected = true
                iv_mute_on_off.setImageResource(R.drawable.audiohome_muteon)
                audio_mute_text.text = "麦克风已开"
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：麦克风已开   channelId:${channelId}")
                voiceManage?.getVoiceApi()?.enableLocalAudio(true)
            }
        }
        //切换线路
        ll_changeRoute.setOnClickListener {

            if (!canChangeRoute) {
                showHangUpTimeTraditionalDialog()
                return@setOnClickListener
            }
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：切换线路   channelId:${channelId}")

            ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "4")
            showChooseDialog(1)
        }
        //挂断
        iv_hang_up.setOnClickListener {
            if (!canHangUp) {
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：挂断，展示提示弹窗   channelId:${channelId}")
                showHangUpTimeOnlineDialog()
                return@setOnClickListener
            }
            if (Utils.isFastClick()) {
                //防止连击
                return@setOnClickListener
            }
            ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "1")
            if (isConnectSuccess) {
                writeAgoraLog("已接通：主叫主动挂断")
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "已接通：主叫主动挂断   channelId:${channelId}")
                updateExpertStatus(false, 1)
                leaveChannel(0)
                uploadLog()
                YDLavManager.instances.callEndStatusUpdate(channelId!!, 51, "主叫挂断")
                callEventSave("51", "已接通：主叫主动挂断")
            } else {
                userCloseCalling(0)
            }

            ActionCountUtils.count(
                "shengwang_popup_layer_page|shengwang_popup_layer_refuse_click",
                YdlCommonRouterManager.getYdlCommonRoute().getUid().toString(),
                uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
            )

        }
        //免提
        iv_hands_free.setOnClickListener {
            ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "3")
            if (iv_hands_free.isSelected) {
                iv_hands_free.isSelected = false
                iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free_unuse)
                hands_free_text.text="扬声器已关"
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：免提，扬声器已关   channelId:${channelId}")
            } else {
                iv_hands_free.isSelected = true
                iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free)
                hands_free_text.text="扬声器已开"
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：免提，扬声器已开   channelId:${channelId}")
            }

            //已经接通
            if (isConnectSuccess) {
                //是否开启外放
                voiceManage?.getVoiceApi()?.setEnableSpeakerphone(iv_hands_free.isSelected)
            } else {
                //未接通
                if (mPlayer != null) {
                    mPlayer?.switchPlayType(iv_hands_free.isSelected)
                }
            }
        }
    }

    /**
     * 请求权限
     */
    @SuppressLint("CheckResult")
    private fun requestPermission() {
        try {
            //申请音频权限
            XXPermissions.with(this) // 申请单个权限
                .permission(com.hjq.permissions.Permission.RECORD_AUDIO)
                .request(object : OnPermissionCallback {
                    override fun onGranted(p0: MutableList<String>?, p1: Boolean) {
                        callEventSave("80", "请求音频权限通过")

                        writeAgoraLog("请求音频权限通过")
                        AliYunRichLogsHelper.getInstance()
                            .sendRichLog(AliYunLogConfig.AGORA, "请求音频权限通过   channelId:${channelId}")
                        init()
                    }

                    override fun onDenied(permissions: MutableList<String>?, never: Boolean) {
                        // 拒绝权限操作发送给服务端
                        uploadException(
                            "AudioNotAuth",
                            "zhu",
                            YDLavManager.AUDIO_NO_AUTH_ERROR_CODE,
                            null
                        )
                        callEventSave("80", "拒绝请求音频权限")

                        writeAgoraLog("拒绝请求音频权限")
                        AliYunRichLogsHelper.getInstance()
                            .sendRichLog(AliYunLogConfig.AGORA, "拒绝请求音频权限   channelId:${channelId}")
                        uploadLog()
                        showStorageDialog()

                    }
                })

        } catch (e: Exception) {
            callEventSave("80", "请求音频权限异常${e.message}")

            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "请求音频权限异常${e.message}   channelId:${channelId}")
            init()
        }

    }

    private fun showStorageDialog() {
        if (mStorageDialog == null) {
            mStorageDialog = ZDialog.Builder(this)
                .setContentView(R.layout.audioim_activity_permission_dialog)
                .setOnClickListener(R.id.cancel_dialog) {
                    mStorageDialog?.dismiss()
                    mStorageDialog = null
                    finish()
                }
                .setAnimation(0)//取消动画
                .setOnClickListener(R.id.dial_right_now) {
                    mStorageDialog?.dismiss()
                    mStorageDialog = null
                    finish()
                    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                    val uri = Uri.fromParts("package", packageName, null)
                    intent.data = uri
                    startActivity(intent)
                }
                .show()
        }
    }

    private fun showHangUpTimeTraditionalDialog() {
        if (mHangUpTimeTraditionalDialog == null) {
            mHangUpTimeTraditionalDialog = ZDialog.Builder(this)
                .setContentView(R.layout.audioim_activity_time_alarm_dialog)
                .setOnClickListener(R.id.dial_right_now) {
                    mHangUpTimeTraditionalDialog?.dismiss()
                    mHangUpTimeTraditionalDialog = null
                }
                .setCancelAble(false)
                .setAnimation(0)//取消动画
                .width((resources.displayMetrics.widthPixels * 0.8f).toInt())
                .show()

            val text = String.format(
                getString(R.string.audioim_audio_time_alarm_msg_tradition_dialog),
                traditionCallTime
            )

            (mHangUpTimeTraditionalDialog?.findDialogView(R.id.third_title) as TextView).text = text
        }
    }

    private fun dismissHangUpTimeTraditionalDialog() {
        if (mHangUpTimeTraditionalDialog != null && mHangUpTimeTraditionalDialog?.isShowing == true) {
            mHangUpTimeTraditionalDialog?.dismiss()
            mHangUpTimeTraditionalDialog = null
        }
    }

    private fun dismissHangUpTimeOnlineDialog() {
        if (mHangUpTimeOnlineDialog != null && mHangUpTimeOnlineDialog?.isShowing == true) {
            mHangUpTimeOnlineDialog?.dismiss()
            mHangUpTimeOnlineDialog = null
        }
    }


    private fun showHangUpTimeOnlineDialog() {
        if (mHangUpTimeOnlineDialog == null) {
            mHangUpTimeOnlineDialog = ZDialog.Builder(this)
                .setContentView(R.layout.audioim_activity_time_alarm_dialog)
                .setOnClickListener(R.id.dial_right_now) {
                    mHangUpTimeOnlineDialog?.dismiss()
                    mHangUpTimeOnlineDialog = null
                }
                .setCancelAble(false)
                .setAnimation(0)//取消动画
                .width((resources.displayMetrics.widthPixels * 0.8f).toInt())
                .show()

            val text = String.format(
                getString(R.string.audioim_audio_time_alarm_msg_online_dialog),
                onlineCallTime
            )
            (mHangUpTimeOnlineDialog?.findDialogView(R.id.third_title) as TextView).text = text
        }
    }


    @SuppressLint("CheckResult", "SetTextI18n")
    private fun init() {
        wave_view.start()
        //初始化声网
        initializeAgoraEngine()
        //发起呼叫
        var msgBean = AudioMessageBean(
            1,
            channelId!!,
            YdlCommonRouterManager.getYdlCommonRoute().getUid().toString(),
            YdlCommonRouterManager.getYdlCommonRoute().getUserInfo()!!.headUrl,
            YdlCommonRouterManager.getYdlCommonRoute().getUserInfo()!!.userName,
            remainTime!!.toInt(),
            totalDuration ?: 1500,
            relationId,
            callId,
            null,
            channelId
        )
        sendDoctocrMsg = Gson().toJson(msgBean)

        writeAgoraLog("主叫(用户)发送通话邀请")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "主叫(用户)发送通话邀请$msgBean    channelId:${channelId}")
        rtcCall()

        //开始50s等待倒计时
        waitDisposable =
            Observable.interval(0, 100, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.computation())
                .take(600).observeOn(AndroidSchedulers.mainThread()).subscribe({
                    val remainTime = 50 - it / 10
                    traditionCallTime = remainTime
                    if (remainTime <= 0) {
                        dismissHangUpTimeTraditionalDialog()
                        waittingStatus()
                    } else {
                        tv_change_time_counter.text = "转传统电话（${remainTime}s）"
                        if (mHangUpTimeTraditionalDialog != null && mHangUpTimeTraditionalDialog?.isShowing == true) {
                            val callTime = String.format(
                                getString(R.string.audioim_audio_time_alarm_msg_tradition_dialog),
                                traditionCallTime
                            )
                            (mHangUpTimeTraditionalDialog?.findDialogView(R.id.third_title) as TextView).text =
                                callTime
                        }
                    }

                    onlineCallTime = remainTime - 20
                    if (remainTime <= 20) {
                        audio_hangup_text.text = "挂断"
                        dismissHangUpTimeOnlineDialog()
                    } else {
                        audio_hangup_text.text = "挂断(${remainTime - 20}s)"
                        if (mHangUpTimeOnlineDialog != null && mHangUpTimeOnlineDialog?.isShowing == true) {
                            val callTime = String.format(
                                getString(R.string.audioim_audio_time_alarm_msg_online_dialog),
                                onlineCallTime
                            )
                            (mHangUpTimeOnlineDialog?.findDialogView(R.id.third_title) as TextView).text =
                                callTime
                        }
                    }
                    var result = it.toFloat() / 3f
                    progress_view.setProgress(result)
                    if (result >= 100f && !canHangUp) {
                        audio_hangup_text.text = "挂断"
                        //挂断按钮可点击
                        canHangUp = true
                        iv_hang_up.setImageResource(R.drawable.audioim_img_hang_up)
                    }

                }, {
                    callEventSave("80", "倒计时异常${it.message}")

                    LogUtil.d(it.message)
                    AliYunRichLogsHelper.getInstance()
                        .sendRichLog(AliYunLogConfig.AGORA, "倒计时异常${it.message}    channelId:${channelId}")

                    dismissHangUpTimeOnlineDialog()

                    dismissHangUpTimeTraditionalDialog()
                }) {
                    //                    waittingStatus()
                    if (!isConnectSuccess) {
                        //关闭音乐


                        dismissHangUpTimeOnlineDialog()

                        dismissHangUpTimeTraditionalDialog()

                        stopPlaying()
                        callEventSave("34", "未接通挂断：50s等待倒计时结束挂断")

                        writeAgoraLog("未接通挂断：50s等待倒计时结束挂断")
                        AliYunRichLogsHelper.getInstance()
                            .sendRichLog(AliYunLogConfig.AGORA, "未接通挂断：50s等待倒计时结束挂断    channelId:${channelId}")
                        //提示切换传统线路
                        //发送消息通知专家用户已挂断
                        YDLavManager.instances.cancelCall(
                            listenerUid!!,
                            channelId!!,
                            sendDoctocrMsg!!
                        ) { msg, code ->
                            callEventSave("51", "未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断")

                            writeAgoraLog("未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断")
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(
                                    AliYunLogConfig.AGORA,
                                    "未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断    channelId:${channelId}"
                                )
                        }
                        //通话结束或挂断时，上传日志文件
                        uploadLog()

                        showToast("暂时无法接通，建议稍后尝试")
                        userCloseCalling(6)
                    }
                }

        //双重保险：加入频道成功，通过服务端发推送给专家
        noticeServerPush(true)
    }

    fun rtcCall() {
        YDLavManager.instances.rtcCall(listenerUid, channelId, sendDoctocrMsg)
        onStartCall()
    }

    /**
     * 声网初始化
     */
    private fun initializeAgoraEngine() {
        /**
         * 创建一个实例
         * param appId            应用id
         * param mRtcEventHandler 事件回调（SDK 通过指定的事件通知应用程序 SDK 的运行事件，如: 加入或离开频道，新用户加入频道等）
         */
        voiceManage = YDLVoiceManager()
        voiceManage?.attachVoiceEventHandler(mRtcEventHandler)
        voiceManage?.getVoiceApi()?.setAudioProfile(Constants.AUDIO_PROFILE_DEFAULT, Constants.AUDIO_SCENARIO_CHATROOM_GAMING)

        voiceManage?.attachNetQualityListener(
            NetQuality(
                this,
                channelId,
                voiceManage,
                tvNetUp,
                ivNetQuality,
                tvNetQuality,
                tvNetDown,
                tvNetDelay,
                layoutQualityGroup
            )
        )

        AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.initSdk))
    }

    /**
     * 声网加入频道
     */
    fun joinChannel() {
        if (hasJoinChannel) return
        callEventSave("20", "对方（专家）接受了通话邀请，主叫（用户）开始加入频道：$channelId")

        writeAgoraLog("对方（专家）接受了通话邀请，主叫（用户）开始加入频道：$channelId")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "对方（专家）接受了通话邀请，主叫（用户）开始加入频道：$channelId")
        AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.join))
        val joinCode = voiceManage?.getVoiceApi()?.joinChannel(
            token!!,
            channelId!!,
            "Extra Optional Data",
            YdlCommonRouterManager.getYdlCommonRoute().getUid()
        )
        if (joinCode != null && joinCode == 0) {
            hasJoinChannel = true
        }
        if (joinCode != null && joinCode < 0) {
            AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.joinFail), retCode = joinCode)
        }
    }

    /**
     * 用户主动挂断（包括：60s专家未接听自动挂断）
     * 注意：这个方法只在专家还未接听的状态才能调用
     *
     */
    private fun userCloseCalling(reason: Int) {
        callEventSave("32", "未接听时：主叫（用户）主动挂断，取消呼叫")

        writeAgoraLog("未接听时：主叫（用户）主动挂断，取消呼叫")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "未接听时：主叫（用户）主动挂断，取消呼叫   channelId:${channelId}")
        LogUtil.e("未接听挂断")
        //发送消息通知专家用户已挂断
        YDLavManager.instances.cancelCall(
            listenerUid!!,
            channelId!!,
            sendDoctocrMsg!!
        ) { msg, code ->
            callEventSave("51", "未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断")

            writeAgoraLog("未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断    channelId:${channelId}")
        }
        //通话结束或挂断时，上传日志文件
        uploadLog()
        handler?.postDelayed({
            LogUtil.e("离开频道")
            leaveChannel(reason)
        }, 100)
    }

    /**
     * 更新专家状态
     *@param isSwitchAxb 是否切换axb
     * @param finishStatus 状态值：     0：开始         1：结束
     */
    private fun updateExpertStatus(isSwitchAxb: Boolean, finishStatus: Int) {
        if (isSwitchAxb) {
            dialPhone()
        }

        if (finishStatus == 0) {
            callStartTime = System.currentTimeMillis()
        }
    }

    /**
     * 线路选择弹窗
     */
    private fun showChooseDialog(type: Int) {
        val dialog =
            AxbConfirmDialog(mContext, type, object : AxbConfirmDialog.OnClickEnsureListener {
                override fun onClickEnsure() {
                    callEventSave("80", "主叫点击切换AXB按钮")

                    writeAgoraLog("主叫点击切换AXB按钮")
                    AliYunRichLogsHelper.getInstance()
                        .sendRichLog(AliYunLogConfig.AGORA, "主叫点击切换AXB按钮   channelId:${channelId}")
                    switchAXB()
                }

                override fun onClose() {
                    // 如果声网未连接成功，切换axb的弹框是自动弹出的，当关闭弹框的时候，执行用户挂断操作
                    // 如果声网连接成功，点击右上角按钮弹出切换axb弹框，但是关闭时用户不执行挂断操作
                    if (!isConnectSuccess) {
                        userCloseCalling(-1)
                    }
                }
            })
        dialog.show()
    }

    /**
     * 切换成axb路线请求
     */
    private fun switchAXB() {
        if (isConnectSuccess) {
            uploadException("", "zhu", "108", object : YDLavManager.UploadExceptionCallback {
                override fun onSuccess() {
                    callEventSave("80", "离开房间成功,主叫切换AXB之后")

                    writeAgoraLog("离开房间成功,主叫切换AXB之后")
                    AliYunRichLogsHelper.getInstance()
                        .sendRichLog(AliYunLogConfig.AGORA, "离开房间成功,主叫切换AXB之后    channelId:${channelId}")
                    mPresenter.getAXBPhone(ConnectCommand(listenId!!, "1"))
                }

            })
            YDLavManager.instances.callEndStatusUpdate(channelId!!, 51, "接通中：主叫主动切换AXB")

        } else {
            mPresenter.getAXBPhone(ConnectCommand(listenId!!, "1"))
        }
    }

    /**
     * 切换axb网络请求结果:axb电话
     *w
     */
    override fun switchAXBResponse(axbPhone: String) {
        this.axbPhone = axbPhone
        isJumpDail = true
        if (isConnectSuccess) {
            //通话结束或挂断时，上传日志文件
            uploadLog()
            //已经连接成功，切换axb时需要更新专家状态
            updateExpertStatus(true, 1)
        } else {
            //未连接成功，切换axb时：需发送消息通知专家端用户已挂断
            //发送消息通知专家用户已挂断
            //发送消息通知专家用户已挂断
            YDLavManager.instances.cancelCall(
                listenerUid!!,
                channelId!!,
                sendDoctocrMsg!!
            ) { msg, code ->
                callEventSave("51", "未接听时：主叫主动挂断失败，msg=$msg($code)，再次挂断")

                writeAgoraLog("未接听时：主叫主动挂断失败，msg=$msg($code)，再次挂断")
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "未接听时：主叫主动挂断失败，msg=$msg($code)，再次挂断   channelId:${channelId}")
            }
            leaveChannel(5)
        }
    }


    /**
     * 跳转拨号界面
     */
    override fun dialPhone() {
        var phoneIntent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:$axbPhone"))
        startActivity(phoneIntent)
        finish()
    }


    /**
     * 60s等待完成，专家未接听
     */
    private fun waittingStatus() {
        tv_change_time_counter.visibility = View.GONE
        //挂断按钮可点击
        canHangUp = true
        iv_hang_up.setImageResource(R.drawable.audioim_img_hang_up)
//        if (!isConnectSuccess) {
//            //页面等待文案调整
//            tv_waiting.visibility = View.GONE
//            tv_change_doctor.text = "对方暂无应答，正在为您切换线路重播"
//            tv_change_doctor.visibility = View.VISIBLE
//        }
        if (!isShowAXB) {
            ll_changeRoute.visibility = View.GONE
        } else {
            //切换线路按钮可见
            canChangeRoute = true
        }

    }

    /**
     * 播放等待音频
     */
    fun playWaitingMusic() {
        if (mPlayer == null) {
            mPlayer = AudioPlayer(this)
        }
        if ((Math.random() * 10 + 1).toInt() >= 5) {
            mPlayer?.setTwoDataAndStart(R.raw.audioim_audio_music_1, R.raw.audioim_loop_music)
        } else {
            mPlayer?.setTwoDataAndStart(R.raw.audioim_audio_music_2, R.raw.audioim_loop_music)
        }
    }

    /**
     * 播放结束音频，音频播放结束后，自动关闭页面
     */
    private fun playFinishMusic() {
        if (mPlayer == null) {
            mPlayer = AudioPlayer(this)
        }
        mPlayer?.setDataSource(R.raw.effect_hand_up)
        mPlayer?.switchPlayType(iv_hands_free.isSelected)
        mPlayer?.setCompletionListener(MediaPlayer.OnCompletionListener {
            LogUtil.e("播放结束")
            //通话剩余时间不足60s时，默认
            if (localRemainTime!! <= 60 && !TextUtils.isEmpty(
                    commentUrl
                )
            ) {
                val h5Params = H5Params(commentUrl!!, "评价")
                NewH5Activity.start(this@AudioHomeActivity, h5Params)
            }
            if (isJumpDail) {
                //跳转拨号界面
                dialPhone()
            }
            finish()
        })
        mPlayer?.start(false, true)
    }

    /**
     * 停止播放
     */
    private fun stopPlaying() {
        if (mPlayer != null) {
            mPlayer?.pause()
        }
    }

    /**
     * sdk通话链接成功
     */
    private fun connectSuccess() {
        isConnectSuccess = true
        phoneHandler?.removeCallbacksAndMessages(null)
        //通知服务端，此次通话已经接通，服务端开始订单
        updateExpertStatus(false, 0)
        //是否开启外放
        voiceManage?.getVoiceApi()?.setEnableSpeakerphone(false)

        if (iv_mute_on_off.isSelected) {
            iv_mute_on_off.setImageResource(R.drawable.audiohome_muteoff)
            audio_mute_text.text = "麦克风已关"
        } else {
            iv_mute_on_off.isSelected = true
            iv_mute_on_off.setImageResource(R.drawable.audiohome_muteon)
            audio_mute_text.text = "麦克风已开"
        }

        hands_free_text.text="扬声器已关"
        iv_hands_free.isSelected = false
        iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free_unuse)
        disposable?.dispose()

        stopPlaying()
        vibrator?.vibrate(1000)

        //等待状态的相关ui隐藏(挂断按钮的倒计时不清除，挂断按钮必须在30s后才能点击)
        tv_change_doctor.visibility = View.GONE
        tv_tips.visibility = View.GONE
        //显示通话相关ui
        rl_remain_time.visibility = View.VISIBLE

        showToast("已接通")

        tv_tips.visibility = View.GONE

        //剩余倾诉时长倒计时
        totalDisposable =
            Observable.interval(0, 1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.computation())
                .take(remainTime!!.toLong() + 1)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    localRemainTime = remainTime!!.toInt().minus(it.toInt())

                    if (localRemainTime == 180) {
                        //三分钟语音播报
                        playNoticeMusic(3)
                    }
                    if (localRemainTime == 60) {
                        //一分钟语音播报
                        playNoticeMusic(1)
                    }
                    if (localRemainTime!! <=60) {
                        if (canChangeRoute) {
                            canChangeRoute = false
                        }
                    }
                    tv_remain_time.text = DateUtils.formatTime(localRemainTime.toString())
                }, {
                    LogUtil.d(it.message)
                }, {
                    leaveChannel(7)
                    uploadLog()
                    callEventSave("50", "倾诉时间已用完")
                    YDLavManager.instances.callEndStatusUpdate(channelId!!, 50, "倾诉时间已用完")
                    //注意：自动挂断时，如果对方离开频道的回调已经触发，就不要再重复调用接口
                    showToast("通话已结束")
                    //通话结束或挂断时，上传日志文件
                    uploadLog()
                    updateExpertStatus(false, 1)
                })
    }

    /**
     * 剩余3min和1min时提示音
     * @param min 1 ：还剩1min   3：还剩3min
     *
     */
    private fun playNoticeMusic(min: Int) {
        if (mPlayer == null) {
            mPlayer = AudioPlayer(this)
        }
        when (min) {
            0 -> {
                //结束音
                mPlayer?.setDataSource(R.raw.audioim_audio_out_channel)
            }

            1 -> {
                //1分钟提示
                mPlayer?.setDataSource(R.raw.audioim_last_1_min)
            }
            3 -> {
                //3分钟提示
                mPlayer?.setDataSource(R.raw.audioim_last_3_min)
            }
        }

        mPlayer?.switchPlayType(iv_hands_free.isSelected)
        mPlayer?.start(false, false)
    }

    /**
     * 用户加入频道后
     *通知服务端发送推送
     * 通知专家加入频道
     * 这个功能已经有用信令通知，为了解决专家信令掉线的问题，增加推送逻辑
     *
     * @param isCall true 拨打   false 取消拨打
     */
    private fun noticeServerPush(isCall: Boolean) {
        var msgBean = AudioMessageBean(
            1,
            channelId!!,
            YdlCommonRouterManager.getYdlCommonRoute().getUid().toString(),
            YdlCommonRouterManager.getYdlCommonRoute().getUserInfo()!!.headUrl,
            YdlCommonRouterManager.getYdlCommonRoute().getUserInfo()!!.userName,
            remainTime!!.toInt(),
            totalDuration ?: 1500,
            relationId,
            callId,
            null,
            channelId
        )
        val cmd = NoticePushCommand()
        cmd.data = msgBean
        cmd.pushId = listenerUid
        if (isCall) {
            cmd.status = "CALL"
        } else {
            cmd.status = "CALL_OFF"
        }
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "用户加入频道后,通知服务端发送推送   channelId:${channelId}")
        mPresenter.noticeServerPush(cmd)
    }

    /**
     * 声网离开频道
     * 未知-1拒绝1网络连接被服务器禁止2对方掉线或离开3主动挂断或取消4被叫接听超时7转AXB8倾诉时间用完9
     * 出异常10，加入通道超时11,声网Error12,页面销毁13
     */
    fun leaveChannel(reason: Int) {
        LogUtil.e("调用leaveChannel方法，isLeavelChannel=$isLeavelChannel")
        if (!isLeavelChannel) {
            isLeavelChannel = true
            playNoticeMusic(0)
            //刷新h5页面
            EventBus.getDefault().post(RefreshWebEvent(false))
            stopPlaying()
            LogUtil.e("播放结束音频")
            //播放结束音频
            playFinishMusic()
            //  声网离开房间
            if (reason in 0..11) {
                val from = LeaveChannelReason.getFrom(reason)
                AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.leave), retCode = from, errorCode = reason)
            } else {
                XLog.e("audiohomeActivity", "leaveChannel$reason")
            }
            voiceManage?.getVoiceApi()?.leaveChannel()
        }
    }

    override fun onResume() {
        super.onResume()
        sensorManager?.registerListener(
            this,
            sensorManager?.getDefaultSensor(Sensor.TYPE_PROXIMITY),
            SensorManager.SENSOR_DELAY_NORMAL
        )
        ActionCountUtils.count(
            "shengwang_popup_layer_page|shengwang_popup_layer_page_visit",
            "",
            uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
        )
    }

    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
    }

    override fun onSensorChanged(event: SensorEvent?) {
        val values = event!!.values
        when (event.sensor.type) {
            Sensor.TYPE_PROXIMITY -> {
                if (values[0] == 0.0f) {
                    //贴近手机
                    if (localWakeLock?.isHeld == false) {
                        localWakeLock?.acquire()
                    }
                } else {
                    //离开手机
                    //唤醒设备
                    if (localWakeLock?.isHeld == true) {
                        localWakeLock?.release()
                    }
                }
            }
        }
    }

    /**
     * 显示自定义弹窗
     */
    private fun showToast(msg: String?) {
        runOnUiThread {
            ToastHelper.show(msg ?: "")
        }
    }

    /**
     * 网络状态
     */
    fun showNetStatus(msg: String, status: Int = 0) {
        LogUtil.e("showNetStatus: msg=$msg,status=$status")
        if (tv_nte_status.visibility == View.VISIBLE) {
            return
        }
        if (TextUtils.isEmpty(msg)) {
            tv_nte_status.visibility = View.GONE
        } else {
            tv_nte_status.text = msg
            if (status == 0) {
                tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(
                    ContextCompat.getDrawable(
                        this,
                        R.drawable.av_audio_wifi_normal
                    ), null, null, null
                )
            }
            if (status == 1) {
                tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(
                    ContextCompat.getDrawable(
                        this,
                        R.drawable.av_audio_wifi_better
                    ), null, null, null
                )
            }
            if (status == -1) {
                tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
            }
            tv_nte_status.visibility = View.VISIBLE
            tv_nte_status.postDelayed({
                tv_nte_status.visibility = View.GONE
            }, 2000)
        }
    }

    override fun showProgressView() {
        try {
            showProgressDialog()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun dismissProgressView() {
        try {
            dismissProgressDialog()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun uploadLog() {
        if (!hasUpLoadLog) {
            hasUpLoadLog = true
            LogHelper.getInstance().uploadLog(false)
        }
    }

    fun uploadExceptionStatus(msg: String, status: Int) {
        callStatus = status
        uploadException(msg, zhu = "zhu", eventType = "108", callback = null)
    }

    /**
     * 上传错误日志
     * zhu 洪平要的，判别是移动端主动调的还是声网返的
     */
    private fun uploadException(
        message: String,
        zhu: String = "",
        eventType: String = "99",
        callback: YDLavManager.UploadExceptionCallback?
    ) {
        val time: String = (System.currentTimeMillis() / 1000).toString()
        val uid: String =
            ModularServiceManager.provide(IUserService::class.java).getUserInfo()?.uid!!
        val payLoad = PayLoad(channelId ?: "0", time, uid, "1", "999", message)
        val connectException =
            ConnectExceptionCommand(time + zhu, "2", eventType, payLoad, callStatus)
        YDLavManager.instances.uploadException(connectException, callback)
    }

    fun writeAgoraLog(content: String, isAppend: Boolean = true) {
        try {
            AudioLogUtils.writeAgoraLog(
                "$content-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}",
                "confide.log",
                isAppend
            )
        } catch (e: Exception) {
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        findRouteService(IImService::class.java).unregisterObserveCustomNotification(notificationCallback)
        uploadLog()
        phoneHandler?.removeCallbacksAndMessages(null)
        if (isConnectSuccess) {
            uploadException("", "zhu", "108", callback = null)
        }
        if (handler != null) {
            handler = null
        }

        if (phoneHandler != null) {
            phoneHandler = null
        }

        hasUpLoadLog = false

        if (waitDisposable != null) {
            waitDisposable?.dispose()
        }
        if (disposable != null) {
            disposable?.dispose()
        }
        if (totalDisposable != null) {
            totalDisposable?.dispose()
        }
        if (sensorManager != null) {
            sensorManager?.unregisterListener(this)
        }
        //唤醒设备
        if (localWakeLock != null && localWakeLock!!.isHeld) {
            localWakeLock?.release()
        }
        sensorManager = null
        localWakeLock = null
        localPowerManager = null

        if (null != voiceManage && null != voiceManage?.getVoiceApi()) {
            if (!isLeavelChannel) {
                //  声网离开房间
                voiceManage?.getVoiceApi()?.leaveChannel()
            }
//            voiceManage?.getVoiceApi()?.destroy()
            voiceManage = null
        }

        if (mPlayer != null) {
            mPlayer?.clear()
            mPlayer = null
        }
    }

    //重写物理返回按钮
    override fun onBackPressed() {
    }

    /**
     *  倾诉日志
     * @param session 通话业务id
     * @param status 状态:01通话中(不影响通话的事件) 10:拨打 20未拨通 30未接通 40 接通 50挂断 60断线 70重连 80 呼叫方信号 90 被呼叫方信号
     * @param res 上报的详细
     * @param line 载体:1.网易 2.中国移动(双呼)3.联通 4.华为 5.糖猫-联通 7:声网 8:微信 10:新移动
     * */
    fun callEventSave(
        status: String,
        res: String,
        session: String? = channelId,
        line: String = "7"
    ) {
        YDLavManager.instances.callEventSave(status, res, session, line)
    }

    private fun onStartCall() {
        val dimension = hashMapOf("conversation" to "start_call", "call" to "call_start")
        onConfideEvent(dimension, channelId)
    }

    private fun onMeJoined() {
        val dimension = hashMapOf("conversation" to "me_joined")
        onConfideEvent(dimension, channelId)
    }

    fun onPeerAccepted() {
        val dimension = hashMapOf("conversation" to "peer_accepted", "call" to "call_accepted")
        onConfideEvent(dimension, channelId)
    }

    private fun onPeerJoined() {
        val dimension = hashMapOf("conversation" to "peer_joined")
        onConfideEvent(dimension, channelId)
    }
}
