package com.tencent.qcloud.tuikit.tuicallkit.manager.bridge

import android.content.Context
import android.text.TextUtils
import android.util.Log
import com.tencent.cloud.tuikit.engine.call.TUICallEngine
import com.tencent.cloud.tuikit.engine.common.TUICommonDefine
import com.tencent.qcloud.tuicore.TUIConstants
import com.tencent.qcloud.tuicore.TUICore
import com.tencent.qcloud.tuicore.TUILogin
import com.tencent.qcloud.tuicore.interfaces.ITUIExtension
import com.tencent.qcloud.tuicore.interfaces.ITUINotification
import com.tencent.qcloud.tuicore.interfaces.ITUIObjectFactory
import com.tencent.qcloud.tuicore.interfaces.ITUIService
import com.tencent.qcloud.tuikit.tuicallkit.TUICallKit
import com.tencent.qcloud.tuikit.tuicallkit.common.data.Constants
import com.tencent.qcloud.tuikit.tuicallkit.manager.CallManager
import com.tencent.qcloud.tuikit.tuicallkit.manager.feature.CallingBellFeature
import com.tencent.qcloud.tuikit.tuicallkit.manager.feature.CallingVibratorFeature
import com.tencent.qcloud.tuikit.tuicallkit.manager.feature.NotificationFeature
import io.trtc.tuikit.atomicxcore.api.call.CallMediaType
import io.trtc.tuikit.atomicxcore.api.call.CallParams
import io.trtc.tuikit.atomicxcore.api.call.CallStore
import io.trtc.tuikit.atomicxcore.api.login.LoginStore
import org.json.JSONException
import org.json.JSONObject

class CallKitService private constructor(context: Context) : ITUINotification, ITUIService, ITUIExtension,
    ITUIObjectFactory {
    private var appContext: Context = context.applicationContext

    init {
        TUICore.registerEvent(
            TUIConstants.TUILogin.EVENT_IMSDK_INIT_STATE_CHANGED,
            TUIConstants.TUILogin.EVENT_SUB_KEY_START_INIT, this
        )
        TUICore.registerEvent(
            TUIConstants.TIMPush.EVENT_IM_LOGIN_AFTER_APP_WAKEUP_KEY,
            TUIConstants.TIMPush.EVENT_IM_LOGIN_AFTER_APP_WAKEUP_SUB_KEY, this
        )
        TUICore.registerEvent(
            TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED,
            TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGIN_SUCCESS, this
        )
        TUICore.registerEvent(
            TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED,
            TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGOUT_SUCCESS, this
        )

        TUICore.registerService(TUIConstants.TUICalling.SERVICE_NAME, this)

        TUICore.registerExtension(TUIConstants.TUIChat.Extension.InputMore.CLASSIC_EXTENSION_ID, this)
        TUICore.registerExtension(TUIConstants.TUIChat.Extension.InputMore.MINIMALIST_EXTENSION_ID, this)
        TUICore.registerExtension(TUIConstants.TUIContact.Extension.GroupProfileItem.MINIMALIST_EXTENSION_ID, this)
        TUICore.registerExtension(TUIConstants.TUIContact.Extension.GroupProfileItem.CLASSIC_EXTENSION_ID, this)
        TUICore.registerExtension(TUIConstants.TUIContact.Extension.FriendProfileItem.CLASSIC_EXTENSION_ID, this)
        TUICore.registerExtension(TUIConstants.TUIContact.Extension.FriendProfileItem.MINIMALIST_EXTENSION_ID, this)
        TUICore.registerExtension(TUIConstants.TUIChat.Extension.ChatNavigationMoreItem.CLASSIC_EXTENSION_ID, this)
        TUICore.registerExtension(TUIConstants.TUIChat.Extension.ChatNavigationMoreItem.MINIMALIST_EXTENSION_ID, this)

        TUICore.registerObjectFactory(TUIConstants.TUICalling.ObjectFactory.FACTORY_NAME, this)
        TUICore.registerExtension(TUIConstants.TUIChat.Extension.ChatViewTopAreaExtension.EXTENSION_ID, this)
    }

    override fun onNotifyEvent(key: String?, subKey: String?, param: Map<String, Any>?) {
        if (TextUtils.isEmpty(key) || TextUtils.isEmpty(subKey)) {
            return
        }
        if (TUIConstants.TUILogin.EVENT_IMSDK_INIT_STATE_CHANGED == key
            && TUIConstants.TUILogin.EVENT_SUB_KEY_START_INIT == subKey
        ) {
            Log.i(TAG, "onNotifyEvent, start, framework: " + Constants.framework)
            if (Constants.framework == Constants.CALL_FRAMEWORK_NATIVE) {
                TUICallKit.createInstance(appContext)
                adaptiveComponentReport()
            }
            setExcludeFromHistoryMessage()
        }
        if (TUIConstants.TIMPush.EVENT_IM_LOGIN_AFTER_APP_WAKEUP_KEY == key
            && TUIConstants.TIMPush.EVENT_IM_LOGIN_AFTER_APP_WAKEUP_SUB_KEY == subKey
        ) {
            val data =
                param?.get(TUIConstants.TIMPush.EVENT_IM_LOGIN_AFTER_APP_WAKEUP_PUSH_MESSAGE_KEY) as Map<String, String>
            Log.i(TAG, "onNotifyEvent: callOfflineData : $data")

            val map = HashMap<String, Any?>()
            map[TUIConstants.TIMPush.NOTIFICATION.PUSH_ID] = data[TUIConstants.TIMPush.NOTIFICATION.PUSH_ID]
            map[TUIConstants.TIMPush.NOTIFICATION.PUSH_EVENT_TIME_KEY] = System.currentTimeMillis() / 1000
            map[TUIConstants.TIMPush.NOTIFICATION.PUSH_EVENT_TYPE_KEY] = 0

            TUICore.callService(
                TUIConstants.TIMPush.SERVICE_NAME, TUIConstants.TIMPush.METHOD_REPORT_NOTIFICATION_CLICKED, map
            )
        }
        if (TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED == key) {
            if (TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGOUT_SUCCESS == subKey) {
                CallStore.shared.hangup(null)
                CallManager.instance.reset()
                // TUICallEngine.destroyInstance() todo 待修复反复登录后收不到离线来电的问题后打开
            } else if (TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGIN_SUCCESS == subKey) {
                initCallEngine()
            }
        }
    }

    private fun adaptiveComponentReport() {
        try {
            val params = JSONObject()
            params.put("framework", 1)
            when {
                TUICore.getService(TUIConstants.TUIChat.SERVICE_NAME) != null ->
                    params.put("component", Constants.CALL_COMPONENT_CHAT)

                else -> params.put("component", Constants.CALL_COMPONENT)
            }
            params.put("language", Constants.CALL_LANGUAGE_KOTLIN)

            val jsonObject = JSONObject()
            jsonObject.put("api", "setFramework")
            jsonObject.put("params", params)
            CallManager.instance.callExperimentalAPI(jsonObject.toString())
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    private fun setExcludeFromHistoryMessage() {
        if (TUICore.getService(TUIConstants.TUIChat.SERVICE_NAME) == null) {
            return
        }
        try {
            val params = JSONObject()
            params.put("excludeFromHistoryMessage", false)
            val jsonObject = JSONObject()
            jsonObject.put("api", "setExcludeFromHistoryMessage")
            jsonObject.put("params", params)
            TUICallEngine.createInstance(appContext).callExperimentalAPI(jsonObject.toString())
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun initCallEngine() {
        val sdkAppId = TUILogin.getSdkAppId()
        val userId = TUILogin.getLoginUser()
        val userSig = TUILogin.getUserSig()
        Log.i(TAG, "sdkAppId=$sdkAppId userId=$userId")
        LoginStore.shared.login(appContext, sdkAppId, userId, userSig, null)
        TUICallEngine.createInstance(appContext).init(sdkAppId, userId, userSig,
            object : TUICommonDefine.Callback {
                override fun onSuccess() {
                    Log.i(TAG, "callEngine init success")
                    val notificationFeature = NotificationFeature(appContext)
                    notificationFeature.registerNotificationBannerChannel()
                    CallingBellFeature(appContext)
                    CallingVibratorFeature(appContext)
                }

                override fun onError(errCode: Int, errMsg: String) {
                    Log.e(TAG, "callEngine init failed, errCode: $errCode, errMsg: $errMsg")
                }
            })
    }


    companion object {
        private const val TAG = "CallKitService"
        private const val CALL_MEMBER_LIMIT = 9

        fun sharedInstance(context: Context): CallKitService {
            return CallKitService(context)
        }
    }

    private fun <T> getOrDefault(map: Map<*, *>?, key: Any, defaultValue: T?): T? {
        if (map == null || map.isEmpty()) {
            return defaultValue
        }
        val value = map[key]
        try {
            if (value != null) {
                return value as T
            }
        } catch (e: ClassCastException) {
            return defaultValue
        }
        return defaultValue
    }

    override fun onCall(method: String?, param: Map<String?, Any?>?): Any? {
        Log.i(TAG, "onCall, method: $method ,param: $param")
        if (TextUtils.isEmpty(method)) {
            return null
        }
        if (null != param && TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_ENABLE_FLOAT_WINDOW, method)) {
            val enableFloatWindow = param[TUIConstants.TUICalling.PARAM_NAME_ENABLE_FLOAT_WINDOW] as Boolean
            Log.i(TAG, "onCall, enableFloatWindow: $enableFloatWindow")
            TUICallKit.createInstance(appContext).enableFloatWindow(enableFloatWindow)
            return null
        }
        if (null != param && TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_ENABLE_MULTI_DEVICE, method)) {
            val enable = param[TUIConstants.TUICalling.PARAM_NAME_ENABLE_MULTI_DEVICE] as Boolean
            Log.i(TAG, "onCall, enableMultiDevice: $enable")
            CallManager.instance.enableMultiDeviceAbility(enable, null)
            return null
        }
//        if (param != null && TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_ENABLE_INCOMING_BANNER, method)) {
//            val enable = param[TUIConstants.TUICalling.PARAM_NAME_ENABLE_INCOMING_BANNER] as Boolean
//            TUICallKit.createInstance(appContext).enableIncomingBanner(enable)
//            return null
//        }
        if (param != null && TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_ENABLE_VIRTUAL_BACKGROUND, method)) {
            val enable = param[TUIConstants.TUICalling.PARAM_NAME_ENABLE_VIRTUAL_BACKGROUND] as Boolean
            TUICallKit.createInstance(appContext).enableVirtualBackground(enable)
            return null
        }
        if (null != param && TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_CALL, method)) {
            val userIDs = getOrDefault<Array<String>>(param, TUIConstants.TUICalling.PARAM_NAME_USERIDS, null)
            val typeString = getOrDefault<String>(param, TUIConstants.TUICalling.PARAM_NAME_TYPE, "")
            val groupID = getOrDefault<String>(param, TUIConstants.TUICalling.PARAM_NAME_GROUPID, "")

            var userIdList: List<String?>? = userIDs?.toList() ?: ArrayList()
            Log.i(TAG, "onCall, groupID: $groupID, userIdList: $userIdList")
            userIdList = userIdList?.filterNotNull()

            var mediaType = CallMediaType.Audio
            if (TUIConstants.TUICalling.TYPE_VIDEO == typeString) {
                mediaType = CallMediaType.Video
            }
            if (userIdList != null) {
                startCall(groupID, userIdList, mediaType)
            }
        }
        return null
    }

    private fun startCall(groupID: String?, userIdList: List<String>, mediaType: CallMediaType) {
        val params = CallParams()
        params.timeout = Constants.CALL_WAITING_MAX_TIME
        if (!groupID.isNullOrEmpty()) {
            params.chatGroupId = groupID
        }
        TUICallKit.createInstance(appContext).calls(userIdList, mediaType, params, null)
    }

    override fun onCreateObject(objectName: String?, param: MutableMap<String?, Any?>?): Any? {
        return null
    }
}