package com.humand.demo.modules.LivestreamService

import com.facebook.react.bridge.*
import com.facebook.react.modules.core.DeviceEventManagerModule
import com.humand.demo.modules.CallService.NativeParticipant
import com.humand.demo.modules.CallService.toWritableMap
import com.humand.demo.NativeRNLivestreamManagerSpec

/**
 * React Native bridge module for LivestreamService.
 */
class RNLivestreamManager(private val reactContext: ReactApplicationContext) :
    NativeRNLivestreamManagerSpec(reactContext) {

    companion object {
        const val NAME = "RNLivestreamManager"
        private var instance: RNLivestreamManager? = null

        fun setInstance(manager: RNLivestreamManager) {
            instance = manager
        }

        fun emitStateChanged(state: String) {
            val params = Arguments.createMap().apply {
                putString("state", state)
            }
            instance?.sendEvent(LivestreamConstants.RNEvents.LIVESTREAM_STATE_CHANGED, params)
        }

        fun emitParticipantsChanged(participants: List<NativeParticipant>, totalCount: Int) {
            val participantsArray = Arguments.createArray()
            participants.forEach { participant ->
                participantsArray.pushMap(participant.toMap().toWritableMap())
            }

            val params = Arguments.createMap().apply {
                putArray("participants", participantsArray)
                putInt("totalCount", totalCount)
            }
            instance?.sendEvent(LivestreamConstants.RNEvents.LIVESTREAM_PARTICIPANTS_CHANGED, params)
        }

        fun emitMediaStateChanged(microphoneEnabled: Boolean, cameraEnabled: Boolean, speakerEnabled: Boolean) {
            val params = Arguments.createMap().apply {
                putBoolean("microphoneEnabled", microphoneEnabled)
                putBoolean("cameraEnabled", cameraEnabled)
                putBoolean("speakerEnabled", speakerEnabled)
            }
            instance?.sendEvent(LivestreamConstants.RNEvents.LIVESTREAM_MEDIA_STATE_CHANGED, params)
        }

        fun emitClosedCaption(text: String, speakerId: String) {
            val params = Arguments.createMap().apply {
                putString("text", text)
                putString("speakerId", speakerId)
            }
            instance?.sendEvent(LivestreamConstants.RNEvents.LIVESTREAM_CLOSED_CAPTION, params)
        }

        fun emitError(message: String) {
            val params = Arguments.createMap().apply {
                putString("error", message)
            }
            instance?.sendEvent(LivestreamConstants.RNEvents.LIVESTREAM_ERROR, params)
        }
    }

    private val livestreamManager: LivestreamManager by lazy {
        LivestreamManager.getInstance(reactContext)
    }

    init {
        setInstance(this)
    }

    override fun getName(): String = NAME

    override fun getConstants(): Map<String, Any> = mapOf(
        "LIVESTREAM_STATE_CHANGED_EVENT" to LivestreamConstants.RNEvents.LIVESTREAM_STATE_CHANGED,
        "LIVESTREAM_PARTICIPANTS_CHANGED_EVENT" to LivestreamConstants.RNEvents.LIVESTREAM_PARTICIPANTS_CHANGED,
        "LIVESTREAM_MEDIA_STATE_CHANGED_EVENT" to LivestreamConstants.RNEvents.LIVESTREAM_MEDIA_STATE_CHANGED,
        "LIVESTREAM_CLOSED_CAPTION_EVENT" to LivestreamConstants.RNEvents.LIVESTREAM_CLOSED_CAPTION,
        "LIVESTREAM_ERROR_EVENT" to LivestreamConstants.RNEvents.LIVESTREAM_ERROR
    )

    @ReactMethod
    override fun startHostLivestream(id: String, providerCallId: String, cameraEnabled: Boolean) {
        livestreamLog("startHostLivestream: id=$id, providerCallId=$providerCallId, camera=$cameraEnabled")
        livestreamManager.startHostLivestream(id, providerCallId, cameraEnabled)
    }

    @ReactMethod
    override fun joinViewerLivestream(id: String, providerCallId: String, isHls: Boolean) {
        livestreamLog("joinViewerLivestream: id=$id, providerCallId=$providerCallId, isHls=$isHls")
        livestreamManager.joinViewerLivestream(id, providerCallId, isHls)
    }

    @ReactMethod
    override fun stopLivestream() {
        livestreamLog("stopLivestream called")
        livestreamManager.stopLivestream()
    }

    @ReactMethod
    override fun leaveLivestream() {
        livestreamLog("leaveLivestream called")
        livestreamManager.leaveLivestream()
    }

    @ReactMethod
    override fun setMicrophoneEnabled(enabled: Boolean) {
        livestreamLog("setMicrophoneEnabled: $enabled")
        livestreamManager.setMicrophoneEnabledFromRN(enabled)
    }

    @ReactMethod
    override fun setCameraEnabled(enabled: Boolean) {
        livestreamLog("setCameraEnabled: $enabled")
        livestreamManager.setCameraEnabledFromRN(enabled)
    }

    @ReactMethod
    override fun switchCamera() {
        livestreamLog("switchCamera called")
        livestreamManager.switchCameraFromRN()
    }

    @ReactMethod
    override fun getLivestreamState(promise: Promise) {
        try {
            val state = livestreamManager.getCurrentState()
            promise.resolve(state.toMap().toWritableMap())
        } catch (e: Exception) {
            promise.reject("GET_LIVESTREAM_STATE_ERROR", e.message)
        }
    }

    @ReactMethod
    override fun setListenersReady() {
        livestreamLog("setListenersReady called")
    }

    @ReactMethod
    override fun addListener(eventName: String) {}

    @ReactMethod
    override fun removeListeners(count: Double) {}

    private fun sendEvent(eventName: String, params: WritableMap?) {
        if (reactContext.hasActiveReactInstance()) {
            reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
                .emit(eventName, params)
        }
    }
}
