package com.adealink.weparty.room.sdk.controller.impl

import android.os.Handler
import com.adealink.frame.base.IError
import com.adealink.frame.room.data.FlowStateInfo
import com.adealink.weparty.room.data.SeatAudioLockError
import com.adealink.weparty.room.sdk.context.IRoomContext
import com.adealink.weparty.room.sdk.controller.BaseController
import com.adealink.weparty.room.sdk.controller.IDeviceController
import com.adealink.weparty.room.sdk.listener.IDeviceListener
import com.adealink.weparty.room.sdk.service.roomService
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.device.DeviceStatus
import io.trtc.tuikit.atomicxcore.api.device.DeviceStore
import io.trtc.tuikit.atomicxcore.api.live.LiveSeatStore
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

class DeviceController(override val ctx: IRoomContext, serialHandler: Handler) :
    BaseController<IDeviceListener>(ctx, serialHandler),
    IDeviceController<IDeviceListener> {

    private val _microphoneStatusFlow = MutableStateFlow<DeviceStatus>(DeviceStatus.OFF)
    override val microphoneStatusFlow: StateFlow<DeviceStatus> = _microphoneStatusFlow.asStateFlow()

    private var seatJob: Job? = null
    private var liveSeatStore: LiveSeatStore? = null

    private var localAudioMute: Boolean = false

    override fun onRoomIn(flowStateInfo: FlowStateInfo) {
        super.onRoomIn(flowStateInfo)
        liveSeatStore = LiveSeatStore.create(flowStateInfo.roomId)
        seatJob = launch {
            roomService.seatController.micSeatsFlow.map {
                it.values.find { it.userInfo.userID == ctx.appSupplier.selfUid }?.userInfo
            }.distinctUntilChanged().collect {
                if (it == null) {
                    _microphoneStatusFlow.update { DeviceStatus.OFF }
                    return@collect
                }
                val microphoneOn = it.allowOpenMicrophone && it.microphoneStatus == DeviceStatus.ON
                _microphoneStatusFlow.update {
                    if (microphoneOn) {
                        DeviceStatus.ON
                    } else {
                        DeviceStatus.OFF
                    }
                }
            }
        }
    }

    override fun onRoomLeaved(flowStateInfo: FlowStateInfo) {
        super.onRoomLeaved(flowStateInfo)
        localAudioMute = false
        seatJob?.cancel()
    }

    override fun isLocalUserMute(): Boolean {
        return localAudioMute
    }

    override fun openLocalMicrophone(onSuccess: (() -> Unit)?, onFail: ((error: IError) -> Unit)?) {
        val seatInfo = roomService.seatController.getMySeatInfo() ?: return
        if (!seatInfo.userInfo.allowOpenMicrophone) {
            onFail?.invoke(SeatAudioLockError())
            return
        }
        localAudioMute = false
        DeviceStore.shared().openLocalMicrophone(null)
        liveSeatStore?.unmuteMicrophone(object : CompletionHandler {
            override fun onFailure(code: Int, desc: String) {
                onFail?.invoke(IError(serverCode = code, msg = desc))
            }

            override fun onSuccess() {
                onSuccess?.invoke()
            }
        })
    }

    override fun closeLocalMicrophone() {
        localAudioMute = true
        liveSeatStore?.muteMicrophone()
    }

    override fun toggleMicrophone(onSuccess: (() -> Unit)?, onFail: ((error: IError) -> Unit)?) {
        if (!isLocalUserMute()) {
            closeLocalMicrophone()
            onSuccess?.invoke()
            return
        }
        openLocalMicrophone(onSuccess, onFail)
    }


}