package com.adealink.weparty.network

import com.adealink.frame.base.fastLazy
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.data.collections.ConcurrentList
import com.adealink.frame.log.Log
import com.adealink.frame.util.runOnUiThread
import com.adealink.weparty.commonui.widget.floatview.FloatViewFactory
import com.adealink.weparty.commonui.widget.floatview.WindowManagerProxy
import com.adealink.weparty.commonui.widget.floatview.data.FloatWindowType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.android.asCoroutineDispatcher
import kotlinx.coroutines.launch

enum class ConnectType {
    BIZ, //业务长链接
    IM //IM服务连接（融云）
}

enum class ConnectStatus {
    Disconnected, //未连接
    ConnectingOrConnected; //已连接或者连接中

    fun isDisconnected(): Boolean {
        return this == Disconnected
    }
}

object ConnectionStatusManager : CoroutineScope {
    private val floatViewFactory by fastLazy { FloatViewFactory() }

    private var connectType2ConnectStatus = hashMapOf<ConnectType, ConnectStatus>()
    private var connectType2ClickListener = hashMapOf<ConnectType, (() -> Unit)?>()
    val serialHandler = Dispatcher.getSerialHandler()
    override val coroutineContext = SupervisorJob() + serialHandler.asCoroutineDispatcher()
    private val connectStatusListeners = ConcurrentList<ConnectStatusListener>()

    fun addConnectStatusListener(listener: ConnectStatusListener) {
        connectStatusListeners.add(listener)
    }

    fun removeConnectStatusListener(listener: ConnectStatusListener) {
        connectStatusListeners.remove(listener)
    }

    fun addReconnectClickListener(type: ConnectType, clickListener: (() -> Unit)?) {
        launch {
            connectType2ClickListener[type] = clickListener
        }
    }

    fun notifyConnectStatus(type: ConnectType, status: ConnectStatus) {
        launch {
            Log.i(TAG_DISCONNECT_TIP, "notifyConnectStatus, type:${type}, status:${status}")
            if (connectType2ConnectStatus[type] == status) {
                Log.e(
                    TAG_DISCONNECT_TIP,
                    "notifyConnectStatus return, status no change. type:${type}, status:${status}"
                )
                return@launch
            }
            connectType2ConnectStatus[type] = status
            updateFloatView()
            runOnUiThread {
                connectStatusListeners.dispatch { it.onConnectStatusChanged(type, status) }
            }
        }
    }

    /**
     * 如果业务服务器长链接断开，显示业务服务器长链接断开状态
     * 如果IM服务断开，显示IM服务断开状态
     * 如果都没有断开，不显示任何状态
     */
    private fun updateFloatView() {
        val bizConnectStatus = connectType2ConnectStatus[ConnectType.BIZ]
        val imConnectStatus = connectType2ConnectStatus[ConnectType.IM]
        Log.i(TAG_DISCONNECT_TIP, "updateFloatView, bizConnectStatus:${bizConnectStatus}, imConnectStatus:${imConnectStatus}")
        if (bizConnectStatus?.isDisconnected() == true || imConnectStatus?.isDisconnected() == true) {
            addDisconnectFloatView(bizConnectStatus == ConnectStatus.Disconnected, imConnectStatus == ConnectStatus.Disconnected)
        } else {
            removeDisconnectFloatView()
        }
    }

    private fun addDisconnectFloatView(bizDisconnected: Boolean, imDisconnected: Boolean) {
//        runOnUiThread {
//            if (WindowManagerProxy.getWindowManager().isFloatViewAdded(FloatWindowType.NETWORK_DISCONNECT_TIP)) {
//                (WindowManagerProxy.getWindowManager().findFloatViewByType(FloatWindowType.NETWORK_DISCONNECT_TIP) as? NetworkReconnectFloatView)?.let {
//                    Log.i(
//                        TAG_DISCONNECT_TIP,
//                        "updateDisconnectFloatView, bizDisconnected:${bizDisconnected}, imDisconnected:${imDisconnected}"
//                    )
//                    it.updateWithConnectType(bizDisconnected, imDisconnected)
//                }
//                return@runOnUiThread
//            }
//
//            val disconnectFloatView =
//                floatViewFactory.createFloatView<NetworkReconnectFloatView>(NetworkReconnectFloatData(MODE_APPLICATION)) ?: return@runOnUiThread
//            disconnectFloatView.updateWithConnectType(bizDisconnected, imDisconnected)
//            disconnectFloatView.setOnClickListener {
//                removeDisconnectFloatView()
//                tryReConnect()
//            }
//            Log.i(
//                TAG_DISCONNECT_TIP,
//                "addDisconnectFloatView, bizDisconnected:${bizDisconnected}, imDisconnected:${imDisconnected}"
//            )
//            WindowManagerProxy.getWindowManager().addView(disconnectFloatView)
//        }
    }

    private fun tryReConnect() {
        connectType2ConnectStatus[ConnectType.BIZ]?.takeIf { it.isDisconnected() }?.let {
            Log.i(TAG_DISCONNECT_TIP, "tryReConnect biz")
            connectType2ClickListener[ConnectType.BIZ]?.invoke()
        }

        connectType2ConnectStatus[ConnectType.IM]?.takeIf { it.isDisconnected() }?.let {
            Log.i(TAG_DISCONNECT_TIP, "tryReConnect im")
            connectType2ClickListener[ConnectType.IM]?.invoke()
        }
    }

    fun removeDisconnectFloatView() {
        runOnUiThread {
            Log.i(
                TAG_DISCONNECT_TIP,
                "removeDisconnectFloatView, disconnectFloatView is add:${
                    WindowManagerProxy.getWindowManager().isFloatViewAdded(FloatWindowType.NETWORK_DISCONNECT_TIP)
                }"
            )
            WindowManagerProxy.getWindowManager().removeFloatViewByType(FloatWindowType.NETWORK_DISCONNECT_TIP, "network resume")
        }
    }

    private const val TAG_DISCONNECT_TIP = "tag_disconnect_tip"
}

interface ConnectStatusListener {
    fun onConnectStatusChanged(type: ConnectType, status: ConnectStatus)
}