package com.ydl.audioim.http

import androidx.annotation.IntDef
import com.google.gson.Gson
import com.ydl.audioim.bean.AgoraTokenResponse
import com.ydl.audioim.bean.CallEventRequestBody
import com.ydl.audioim.bean.ConnectBean
import com.ydl.audioim.http.command.ConnectCommand
import com.ydl.audioim.http.command.ConnectExceptionCommand
import com.ydl.audioim.http.command.NoticePushCommand
import com.ydl.consultantim.bean.ListenTokenBean
import com.ydl.consultantim.command.ListenTokenCmd
import com.ydl.ydlcommon.data.http.BaseAPIResponse
import com.ydl.ydlcommon.data.http.BaseResponse
import com.ydl.ydlcommon.data.http.RxUtils
import com.ydl.ydlcommon.utils.NetworkParamsUtils
import com.ydl.ydlcommon.utils.TimeUtil
import com.ydl.ydlnet.YDLHttpUtils
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import java.util.*

/**
 * @author jiucheng
 * @描述:声网业务接口请求
 * @Copyright Copyright (c) 2018
 * @Company 壹点灵
 * @date 2018/11/9
 */
class AudioApiRequestUtil {
    companion object {
        /**
         * 倾诉
         */
        fun connectListen(cmd: ConnectCommand): Observable<BaseAPIResponse<ConnectBean>> {
            return RxUtils.mapObservable(cmd)
                .flatMap { it ->
                    YDLHttpUtils.obtainApi(AudioNetAPi::class.java).connectListen(it)
                }
        }

        /**
         * 通话开始回调
         *
         * @param param
         * @return
         */
//        fun connectStart(param: ConnectStartCommand): Observable<BaseAPIResponse<Any>> {
////            val list = YdlRetrofitUtils.getPostList(param)
//            var str = Gson().toJson(param)
//            val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), str) as RequestBody
//            return YDLHttpUtils.obtainApi(AudioNetAPi::class.java).connectStart(body)
//        }

        /**
         * 通话结束回调
         *
         * @param param
         * @return
         */
//        fun connectFinish(param: ConnectFinishCommand): Observable<BaseAPIResponse<Any>> {
////            val list = YdlRetrofitUtils.getPostList(param)
//            var str = Gson().toJson(param)
//            val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), str) as RequestBody
//            return YDLHttpUtils.obtainApi(AudioNetAPi::class.java).connectFinish(body)
//        }

        /**
         * 通话警告与异常回调
         *
         * @param param
         * @return
         */
        fun connectException(param: ConnectExceptionCommand): Observable<BaseAPIResponse<Any>> {
            var str = Gson().toJson(param)
            val body = RequestBody.create(
                MediaType.parse("application/json; charset=utf-8"),
                str
            ) as RequestBody
            return YDLHttpUtils.obtainApi(AudioNetAPi::class.java).connectException(body)
        }

        /**
         * 通知服务端发送推送
         */
        fun noticeServerPush(param: NoticePushCommand): Observable<BaseResponse<Any>> {
            var str = Gson().toJson(param)
            val body = RequestBody.create(
                MediaType.parse("application/json; charset=utf-8"),
                str
            ) as RequestBody
            return YDLHttpUtils.obtainApi(AudioNetAPi::class.java).noticeServerPush(body)
        }

        /**
         * 获取声网登录token
         */
        fun getAgoraToken(): Observable<BaseAPIResponse<AgoraTokenResponse>> {
            return YDLHttpUtils.obtainApi(AudioNetAPi::class.java).getAgoraToken()
        }

        /**
         * 获取声网登录token
         */
        fun listenToken(cmd: ListenTokenCmd): Observable<BaseResponse<ListenTokenBean>> {
            return YDLHttpUtils.obtainApi(AudioNetAPi::class.java)
                .listenToken(NetworkParamsUtils.getMaps(cmd))
        }

        fun callEventSave(
            session: String?,
            line: String,
            status: String,
            response: String?,
            remark: String? = null,
            eventType: String? = null
        ): Observable<BaseAPIResponse<Any>> {
            val eventTime = TimeUtil.getNowDatetime()
            val param = CallEventRequestBody(session, line, status, response, eventTime, remark, eventType);
            val str = Gson().toJson(param)
            val body = RequestBody.create(
                MediaType.parse("application/json; charset=utf-8"),
                str
            ) as RequestBody
            return YDLHttpUtils.obtainApi(AudioNetAPi::class.java).callEventSave(body)
        }

        fun reportCallEvent(
            session: String?,
            event: CallEvent,
            retCode: Int? = null,
            errorCode: Int? = null,
            errorReason: String? = null,
            @ReportLevel reportLevel: Int? = null
        ) {
            if (session == null) return
            val type = event.eventType.name.lowercase(Locale.getDefault())
            val resp = hashMapOf<String, Any>(
                "name" to event.name,
                "desc" to event.desc,
                "reportLevel" to (reportLevel ?: event.reportLevel),
            )
            if (retCode != null) {
                resp["retCode"] = retCode
            }
            if (errorCode != null) {
                resp["errorCode"] = errorCode
            }
            if (errorReason != null) {
                resp["errorReason"] = errorReason
            }
            val response = Gson().toJson(resp)
            callEventSave(session, "7", "20", response, eventType = type).subscribeOn(Schedulers.io()).subscribe()
        }
    }
}

const val REPORT_LEVEL_INFO = 1
const val REPORT_LEVEL_WARN = 2
const val REPORT_LEVEL_ERROR = 3

enum class EventType {
    RTC, IM, LOGIN, DEVICE
}

@IntDef(REPORT_LEVEL_INFO, REPORT_LEVEL_WARN, REPORT_LEVEL_ERROR)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
annotation class ReportLevel

sealed class CallEvent(val eventType: EventType, val name: String, val desc: String, @ReportLevel val reportLevel: Int)

class RtcEvent(val event: Event) :
    CallEvent(EventType.RTC, event.name, event.desc, event.reportLevel) {
    @Suppress("EnumEntryName")
    enum class Event(val desc: String, @ReportLevel val reportLevel: Int) {
        initSdk("初始化SDK", REPORT_LEVEL_WARN),
        join("本地加入房间", REPORT_LEVEL_WARN),
        joinSuccess("加入房间成功", REPORT_LEVEL_INFO),
        joinFail("加入房间失败", REPORT_LEVEL_ERROR),
        remoteJoin("远端加入房间", REPORT_LEVEL_WARN),
        remoteJoinTimeout("远端加入超时", REPORT_LEVEL_WARN),
        leave("本地离开房间", REPORT_LEVEL_WARN),
        remoteLeave("远端离开房间", REPORT_LEVEL_WARN),
        localFirstFrame("本地音频首帧", REPORT_LEVEL_WARN),
        remoteFirstFrame("远端音频首帧", REPORT_LEVEL_WARN),
        networkTypeChanged("网络变化", REPORT_LEVEL_WARN),
        networkDownPoor("网络下行质量差", REPORT_LEVEL_WARN),
        networkUpPoor("网络上行质量差", REPORT_LEVEL_WARN),
        connectionChanged("连接状态变化", REPORT_LEVEL_WARN),
        errorOccurred("错误发生", REPORT_LEVEL_ERROR),
    }
}


class IMEvent(event: Event) : CallEvent(EventType.IM, event.name, event.desc, event.reportLevel) {
    @Suppress("EnumEntryName")
    enum class Event(val desc: String, @ReportLevel val reportLevel: Int) {
        rtmLogin("登录RTM", REPORT_LEVEL_INFO),
        rtmLogout("登出RTM", REPORT_LEVEL_INFO),
        loginSuccess("登录成功", REPORT_LEVEL_INFO),
        loginFail("登录失败", REPORT_LEVEL_ERROR),
        onlineStatusChange("在线状态变化", REPORT_LEVEL_WARN),
        startCall("开始呼叫", REPORT_LEVEL_INFO),
        onPeerReceived("到达对方", REPORT_LEVEL_INFO),
        onPeerAccepted("对方已接受", REPORT_LEVEL_INFO),
        onPeerRejected("对方已拒绝", REPORT_LEVEL_WARN),
        callSuccess("呼叫成功", REPORT_LEVEL_INFO),
        callFail("呼叫失败", REPORT_LEVEL_ERROR),
        callCancel("呼叫取消", REPORT_LEVEL_WARN),
    }
}

class LoginEvent(event: Event) :
    CallEvent(EventType.LOGIN, event.name, event.desc, event.reportLevel) {
    @Suppress("EnumEntryName")
    enum class Event(val desc: String, @ReportLevel val reportLevel: Int) {
        userLogin("用户登录", REPORT_LEVEL_INFO),
        userLogout("用户登出", REPORT_LEVEL_INFO),
        userLoginSuccess("登录成功", REPORT_LEVEL_INFO),
        userLoginFail("登录失败", REPORT_LEVEL_ERROR),
    }
}

class DeviceEvent(event: Event) :
    CallEvent(EventType.DEVICE, event.name, event.desc, event.reportLevel) {
    @Suppress("EnumEntryName")
    enum class Event(val desc: String, @ReportLevel val reportLevel: Int) {
        beForeground("回到前台", REPORT_LEVEL_INFO),
        beBackground("进入后台", REPORT_LEVEL_WARN),
        onTrimMemory("内存使用等级", REPORT_LEVEL_WARN),
        onLowMemory("内存低", REPORT_LEVEL_WARN),
    }
}


object LeaveChannelReason {
    val LeaveChannelReasonNormal = 0
    val LeaveChannelReasonRefuse = 1
    val LeaveChannelReasonCancel = 2
    val LeaveChannelReasonOfflineWithError = 3
    val LeaveChannelReasonOfflineNormal = 4
    val LeaveChannelReasonTurnToAXB = 5
    val LeaveChannelReasonAnswerTimeOut = 6
    val LeaveChannelReasonSystemTimeup = 7
    val LeaveChannelReasonJoinChannelTimeOut = 8
    val LeaveChannelReasonRtcError = 9
    val LeaveChannelReasonKickedByServer = 10
    val LeaveChannelReasonPageError = 11
    fun getFrom(reason: Int): Int {
        return when (reason) {
            1, 3, 4, 6, 8 -> 2
            7, 10 -> 0
            else -> 1
        }
    }
}