package com.adealink.weparty.room.chatroom.page.dispatchcenter

import android.Manifest
import android.content.Intent
import android.view.View
import androidx.appcompat.widget.AppCompatImageView
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import com.adealink.frame.aab.util.getCompatString
import com.adealink.frame.base.fastLazy
import com.adealink.frame.dot.NumDot
import com.adealink.frame.ext.isViewBindingValid
import com.adealink.frame.mvvm.view.viewBinding
import com.adealink.frame.util.onClick
import com.adealink.weparty.commonui.BaseFragment
import com.adealink.weparty.commonui.ext.gone
import com.adealink.weparty.commonui.ext.show
import com.adealink.weparty.commonui.widget.operatebox.OperateBox
import com.adealink.weparty.commonui.widget.operatebox.OperateBoxItem
import com.adealink.weparty.module.profile.ProfileModule
import com.adealink.weparty.module.room.data.MIC_ASSIGN_BY_REMOTE
import com.adealink.weparty.module.room.listener.IRoomOperateItemListener
import com.adealink.weparty.permission.PermissionUtils
import com.adealink.weparty.room.R
import com.adealink.weparty.room.applymic.ApplyMicDialog
import com.adealink.weparty.room.applymic.ApplyMicListDialog
import com.adealink.weparty.room.applymic.ApplyMicStore
import com.adealink.weparty.room.applymic.ApplyMicStore.onRecordChangedLD
import com.adealink.weparty.room.applymic.HostApplyMicListDialog
import com.adealink.weparty.room.chat.ChatInputDialog
import com.adealink.weparty.room.databinding.FragmentDispatchRoomBottomOperateBinding
import com.adealink.weparty.room.gift.RoomGiftPanelDialog
import com.adealink.weparty.room.micseat.dispatcenter.MIC_GUEST
import com.adealink.weparty.room.micseat.dispatcenter.MIC_HOST
import com.adealink.weparty.room.sdk.service.roomService
import com.adealink.weparty.room.setting.RoomSettingDialog
import io.trtc.tuikit.atomicxcore.api.device.DeviceStatus
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach

open class DispatchRoomBottomOperateFragment : BaseFragment(R.layout.fragment_dispatch_room_bottom_operate),
    IRoomOperateItemListener {

    companion object {
        val OPERATE_BTN_MIC = R.id.id_bottom_operate_mic
        val OPERATE_BTN_GIFT = R.id.id_bottom_operate_gift
        val OPERATE_BTN_SETTING = R.id.id_bottom_operate_setting

        //从左到右层级顺序
        private val OPERATE_ITEM_LAYER = intArrayOf(
            OPERATE_BTN_MIC,
            OPERATE_BTN_GIFT,
            OPERATE_BTN_SETTING
        )
    }

    private val binding by viewBinding(FragmentDispatchRoomBottomOperateBinding::bind)

    private val dispatchEventViewModel by activityViewModels<DispatchRoomEventViewModel>()
    private val micOperateItem by fastLazy {
        OperateBoxItem<AppCompatImageView, View>(
            id = OPERATE_BTN_MIC,
            itemView = {
                AppCompatImageView(requireContext()).apply {
                    setImageResource(
                        if (roomService.deviceController.isLocalUserMute()) {
                            R.drawable.room_operate_mic_off_ic
                        } else {
                            R.drawable.room_operate_mic_on_ic
                        }
                    )
                }
            }
        )
    }

    private val giftOperateItem by fastLazy {
        OperateBoxItem<AppCompatImageView, View>(
            id = OPERATE_BTN_GIFT,
            itemView = {
                AppCompatImageView(requireContext()).apply {
                    setImageResource(
                        R.drawable.room_operate_gift_ic
                    )
                }
            }
        )
    }

    private val settingOperateItem by fastLazy {
        OperateBoxItem<AppCompatImageView, View>(
            id = OPERATE_BTN_SETTING,
            itemView = {
                AppCompatImageView(requireContext()).apply {
                    setImageResource(R.drawable.room_operate_setting_ic)
                }
            }
        )
    }

    override fun initViews() {
        binding.operateBox.setLayersDefine(OPERATE_ITEM_LAYER)
        binding.operateBox.setListener(object : OperateBox.OperateBoxListener {
            override fun onOperateItemClick(item: OperateBoxItem<*, *>) {
                this@DispatchRoomBottomOperateFragment.onItemClick(item)
            }
        })

        binding.clInput.setOnClickListener {
            inputBoxClick()
        }
        binding.btnApplyPending.onClick {
            clickApplyMicPending()
        }
        binding.btnApplyMic.onClick {
            ApplyMicDialog().apply {
                if (ProfileModule.getMyUserInfo()?.isPlaymate() == true) {
                    setApplyMic(MIC_ASSIGN_BY_REMOTE)
                } else {
                    setApplyMic(MIC_GUEST)
                }
            }.show(childFragmentManager)
        }
        binding.btnLeaveMic.onClick {
            onLeaveMicClick()
        }
        updateOperateBoxBy()
    }

    override fun observeViewModel() {
        super.observeViewModel()
        dispatchEventViewModel.applyMicNumberLD.observe(viewLifecycleOwner) {
            updateApplyMic(it)
        }
        onRecordChangedLD.observeWithoutCache(viewLifecycleOwner) {
            updateApplyMic()
        }
        roomService.seatController.micSeatsFlow.map {
            it.values.find { it.userInfo.userID == ProfileModule.getMyUid() } != null
        }.distinctUntilChanged().onEach { isOnMic ->
            showMicIcon(isOnMic)
            showRoomSettingIcon()
            updateApplyMic(isOnMic = isOnMic)
        }.launchIn(lifecycleScope)

        roomService.deviceController.microphoneStatusFlow.onEach { status ->
            updateMicIcon(status == DeviceStatus.OFF)
        }.launchIn(lifecycleScope)
    }

    private fun updateOperateBoxBy() {
        binding.operateBox.apply {
            removeAllItems()
            if (roomService.seatController.isOnMic(ProfileModule.getMyUid())) {
                addItem(micOperateItem)
            }
            addItem(giftOperateItem)
            if (roomService.joinController.isOwner() || roomService.seatController.getMyMicIndex() == MIC_HOST) {
                addItem(settingOperateItem)
            }
        }
    }

    private fun updateApplyMic(
        applyNumber: Int = dispatchEventViewModel.applyMicNumber,
        isOnMic: Boolean = roomService.seatController.isOnMic(ProfileModule.getMyUid())
    ) {
        val roomId = roomService.joinController.getJoinedRoomId()
        if (roomId.isNullOrEmpty()) {
            //申请上麦
            binding.btnApplyMic.show()
            //申请列表
            binding.btnApplyPending.gone()
            binding.vApplyPendingDot.gone()
            //下麦
            binding.btnLeaveMic.gone()
            return
        }
        if (isOnMic) {
            //我在麦上
            val micIndex = roomService.seatController.getMicSeatIndex(ProfileModule.getMyUid())
            if (micIndex == MIC_HOST) {
                //申请上麦
                binding.btnApplyMic.gone()
                //申请列表
                binding.btnApplyPending.show()
                binding.btnApplyPending.text = getCompatString(R.string.room_apply_mic_requests)
                binding.vApplyPendingDot.show(NumDot(applyNumber))
                //下麦
                binding.btnLeaveMic.gone()
            } else {
                //申请上麦
                binding.btnApplyMic.gone()
                //申请列表
                binding.btnApplyPending.gone()
                binding.vApplyPendingDot.gone()
                //下麦
                binding.btnLeaveMic.show()
            }
            return
        }
        binding.btnLeaveMic.gone()

        val hasApply = ApplyMicStore.hasApply(roomId)
        if (hasApply) {
            //申请上麦
            binding.btnApplyMic.gone()
            //申请列表
            binding.btnApplyPending.show()
            binding.btnApplyPending.text = getCompatString(R.string.room_apply_mic_pending)
            binding.vApplyPendingDot.show(NumDot(applyNumber))
            return
        }
        binding.btnApplyMic.show()
        binding.btnApplyPending.gone()
        binding.vApplyPendingDot.gone()
    }

    private fun clickApplyMicPending() {
        val isOnMic = roomService.seatController.isOnMic(ProfileModule.getMyUid())
        if (!isOnMic) {
            ApplyMicListDialog().show(childFragmentManager)
            return
        }
        val micIndex = roomService.seatController.getMicSeatIndex(ProfileModule.getMyUid())
        if (micIndex != MIC_HOST) {
            ApplyMicListDialog().show(childFragmentManager)
            return
        }
        HostApplyMicListDialog().show(childFragmentManager)
    }

    private fun updateMicIcon(mute: Boolean) {
        binding.operateBox.findItem(micOperateItem)?.getItemView()?.setImageResource(
            if (mute) R.drawable.room_operate_mic_off_ic else R.drawable.room_operate_mic_on_ic
        )
    }

    fun showRoomSettingIcon(show: Boolean = roomService.joinController.isOwner() || roomService.seatController.getMyMicIndex() == MIC_HOST) {
        if (show) {
            binding.operateBox.addItem(settingOperateItem)
        } else {
            binding.operateBox.removeItem(settingOperateItem)
        }
    }

    open fun showMicIcon(show: Boolean) {
        if (show) {
            binding.operateBox.addItem(micOperateItem)
        } else {
            binding.operateBox.removeItem(micOperateItem)
        }
    }

    private fun onItemClick(item: OperateBoxItem<*, *>) {
        when (item) {
            micOperateItem -> {
                onMicIconClick()
            }

            giftOperateItem -> {
                onGiftIconClick()
            }

            settingOperateItem -> {
                onSettingClick()
            }
        }
    }

    private fun onMicIconClick() {
        if (roomService.deviceController.isLocalUserMute()) {
            requestRecordAudioPermission { granted ->
                if (granted) {
                    roomService.deviceController.toggleMicrophone()
                }
            }
            return
        }
        roomService.deviceController.toggleMicrophone()
    }

    private fun requestRecordAudioPermission(callback: ((granted: Boolean) -> Unit)) {
        PermissionUtils.requestPermissionWithRetry(
            requireActivity(),
            Manifest.permission.RECORD_AUDIO,
            getCompatString(R.string.room_record_audio_permission_tip),
            0,
        ) { granted, recordAudioTipLimited ->
            callback.invoke(granted)
        }
    }

    private fun onGiftIconClick() {
        RoomGiftPanelDialog().show(childFragmentManager)
    }

    private fun inputBoxClick() {
        ChatInputDialog().show(childFragmentManager)
    }

    private fun onSettingClick() {
        RoomSettingDialog().show(childFragmentManager)
    }

    private fun onLeaveMicClick() {
        roomService.seatController.micOff()
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        loadData()
    }

    override fun getOperateItemById(itemId: Int): View? {
        if (!isViewBindingValid()) {
            return null
        }
        return binding.operateBox.findItem(itemId)
    }

    fun showJoinGuideButton(show: Boolean) {
        if (!isViewBindingValid()) {
            return
        }
        binding.btnApplyMicGuide.show(show)
    }
}