package kr.co.vividnext.sodalive.agora

import android.content.Context
import com.orhanobut.logger.Logger
import io.agora.rtc2.Constants
import io.agora.rtc2.IRtcEngineEventHandler
import io.agora.rtc2.RtcEngine
import io.agora.rtm.ErrorInfo
import io.agora.rtm.ResultCallback
import io.agora.rtm.RtmChannel
import io.agora.rtm.RtmChannelListener
import io.agora.rtm.RtmClient
import io.agora.rtm.RtmClientListener
import io.agora.rtm.SendMessageOptions
import kr.co.vividnext.sodalive.BuildConfig
import kr.co.vividnext.sodalive.live.room.LiveRoomRequestType
import kotlin.concurrent.thread

class Agora(
    private val context: Context,
    private val rtcEventHandler: IRtcEngineEventHandler,
    private val rtmClientListener: RtmClientListener
) {
    // RTM client instance
    private var rtmClient: RtmClient? = null

    // RTM channel instance
    private var rtmChannel: RtmChannel? = null

    private var rtcEngine: RtcEngine? = null

    init {
        initAgoraEngine()
    }

    private fun initAgoraEngine() {
        try {
            rtcEngine = RtcEngine.create(
                context,
                BuildConfig.AGORA_APP_ID,
                rtcEventHandler
            )

            rtcEngine!!.setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING)
            rtcEngine!!.setAudioProfile(
                Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY_STEREO,
                Constants.AUDIO_SCENARIO_GAME_STREAMING
            )
            rtcEngine!!.enableAudio()
            rtcEngine!!.enableAudioVolumeIndication(500, 3, true)

            rtmClient = RtmClient.createInstance(
                context,
                BuildConfig.AGORA_APP_ID,
                rtmClientListener
            )
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun deInitAgoraEngine() {
        if (rtcEngine != null) {
            rtcEngine!!.leaveChannel()

            thread {
                RtcEngine.destroy()
                rtcEngine = null
            }
        }

        rtmChannel?.leave(null)
        rtmChannel?.release()
        rtmClient?.logout(null)
    }

    fun inputChat(message: String) {
        val rtmMessage = rtmClient!!.createMessage()
        rtmMessage.text = message

        rtmChannel!!.sendMessage(
            rtmMessage,
            object : ResultCallback<Void?> {
                override fun onSuccess(p0: Void?) {
                    Logger.e("sendMessage - onSuccess")
                }

                override fun onFailure(p0: ErrorInfo) {
                    Logger.e("sendMessage fail - ${p0.errorCode}")
                    Logger.e("sendMessage fail - ${p0.errorDescription}")
                }
            }
        )
    }

    fun joinRtcChannel(uid: Int, rtcToken: String, channelName: String) {
        rtcEngine!!.joinChannel(
            rtcToken,
            channelName,
            "",
            uid
        )
    }

    fun createRtmChannelAndLogin(
        uid: String,
        rtmToken: String,
        channelName: String,
        rtmChannelListener: RtmChannelListener,
        rtmChannelJoinSuccess: () -> Unit,
        rtmChannelJoinFail: () -> Unit
    ) {
        rtmChannel = rtmClient!!.createChannel(channelName, rtmChannelListener)
        rtmClient!!.login(
            rtmToken,
            uid,
            object : ResultCallback<Void> {
                override fun onSuccess(p0: Void?) {
                    rtmChannel!!.join(object : ResultCallback<Void> {
                        override fun onSuccess(p0: Void?) {
                            Logger.e("rtmChannel join - onSuccess")
                            rtmChannelJoinSuccess()
                        }

                        override fun onFailure(p0: ErrorInfo?) {
                            rtmChannelJoinFail()
                        }
                    })
                }

                override fun onFailure(p0: ErrorInfo?) {
                }
            }
        )
    }

    fun sendRawMessageToGroup(
        rawMessage: ByteArray,
        onSuccess: (() -> Unit)? = null,
        onFailure: (() -> Unit)? = null
    ) {
        val message = rtmClient!!.createMessage()
        message.rawMessage = rawMessage
        rtmChannel!!.sendMessage(
            message,
            object : ResultCallback<Void?> {
                override fun onSuccess(p0: Void?) {
                    Logger.e("sendMessage - onSuccess")
                    onSuccess?.invoke()
                }

                override fun onFailure(p0: ErrorInfo) {
                    Logger.e("sendMessage fail - ${p0.errorCode}")
                    Logger.e("sendMessage fail - ${p0.errorDescription}")
                    onFailure?.invoke()
                }
            }
        )
    }

    fun setClientRole(role: Int) {
        rtcEngine!!.setClientRole(role)
    }

    fun muteLocalAudioStream(muted: Boolean) {
        rtcEngine?.muteLocalAudioStream(muted)
    }

    fun muteAllRemoteAudioStreams(mute: Boolean) {
        rtcEngine?.muteAllRemoteAudioStreams(mute)
    }

    fun sendRawMessageToPeer(
        receiverUid: String,
        requestType: LiveRoomRequestType? = null,
        rawMessage: ByteArray? = null,
        onSuccess: () -> Unit
    ) {
        val option = SendMessageOptions()

        val message = rtmClient!!.createMessage()
        message.rawMessage = rawMessage ?: requestType.toString().toByteArray()

        rtmClient!!.sendMessageToPeer(
            receiverUid,
            message,
            option,
            object : ResultCallback<Void?> {
                override fun onSuccess(aVoid: Void?) {
                    onSuccess()
                }

                override fun onFailure(errorInfo: ErrorInfo) {
                }
            }
        )
    }

    fun rtmChannelIsNull(): Boolean {
        return rtmChannel == null
    }

    fun getConnectionState(): Int {
        return rtcEngine!!.connectionState
    }
}
