package com.lanyun.wanglaotou.viewModel

import android.util.Log
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.lanyun.common.base.BaseViewModel
import com.lanyun.common.baseDate.updateMainEvent
import com.lanyun.common.model.MainEvent
import com.lanyun.net.ext.*
import com.lanyun.wanglaotou.model.NodeModel
import com.lanyun.wanglaotou.model.UserSubModel
import com.lanyun.wanglaotou.public.PageState
import com.lanyun.wanglaotou.repo.HomeRepo
import com.lanyun.wanglaotou.util.AngConfigManager
import com.lanyun.wanglaotou.util.MmkvManager
import com.lanyun.wanglaotou.util.SpeedtestUtil
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.receiveAsFlow
import org.w3c.dom.Node

class NodeViewModel : BaseViewModel() {

    private val tcpingTestScope by lazy { CoroutineScope(Dispatchers.IO) }


    var viewStates by mutableStateOf(NodeViewState())
        private set
    private val _viewEvents = Channel<NodeViewEvent>(Channel.BUFFERED)
    val viewEvents = _viewEvents.receiveAsFlow()

    init {
        dispatch(NodeViewAction.UserNode)
    }

    fun dispatch(action: NodeViewAction) {
        when (action) {
            is NodeViewAction.UserNode -> {
                if (isLogin())
                    getNodes()
            }
            is NodeViewAction.UpdateSelect -> {
                updateSelect(action.selectedIndex)
            }
            is NodeViewAction.UpdateExpanded ->{
                updateExpanded(action.expanded)
            }
            is NodeViewAction.NodeRefresh -> {
                if (isLogin())
                    getNodes(action.isRefresh)
            }
        }
    }


    private fun updateSelect(selectedIndex: Int) {
        viewStates = viewStates.copy(selectedIndex = selectedIndex)

    }
    private fun updateExpanded(expanded: Boolean) {
        viewStates = viewStates.copy(expanded = expanded)
    }

    fun getMs(gui:String) : String{
        val aff = MmkvManager.decodeServerAffiliationInfo(gui)
        return aff?.getTestDelayString() ?: ""
    }

    fun getSelectNode() : NodeModel?{
        return MmkvManager.decodeSelectServer()
    }

    fun selectNode(nodeModel: NodeModel){
        MmkvManager.encodeSelectServer(nodeModel)
        updateMainEvent(MainEvent.MainNodeUpdate,true)
    }

    fun testAllTcping() {
        val serversCache = AngConfigManager.serversCache
        tcpingTestScope.coroutineContext[Job]?.cancelChildren()
        SpeedtestUtil.closeAllTcpSockets()
        MmkvManager.clearAllTestDelayResults()
        for (item in serversCache) {
            val serverAddress =  item.nodeModel.host
            val serverPort =  item.nodeModel.port
            tcpingTestScope.launch {
                val testResult = SpeedtestUtil.tcping(serverAddress, serverPort)
                launch(Dispatchers.Main) {
                    MmkvManager.encodeServerTestDelayMillis(item.guid, testResult)
                    viewStates = viewStates.copy(updateListAction = getPosition(item.guid))
                }
            }
        }

    }


    private fun getPosition(guid: String) : Int {
        val serversCache = AngConfigManager.serversCache
        serversCache.forEachIndexed { index, it ->
            if (it.guid == guid)
                return index
        }
        return -1
    }

    fun getNodes(isRefresh:Boolean = false) = serverAwait {

        if (isRefresh){
            showLoading()
            viewStates = viewStates.copy(pageState = PageState.LoadingDialog)
        }

        HomeRepo.getServer().serverData().onSuccess {
            onBizError { code, error_message ->
                hidLoading()
                viewStates = viewStates.copy(pageState = PageState.Error(
                    error_message ?: ""
                ))
            }
            onBizOK<List<NodeModel>> { code, data, error_message ->
                //MmkvManager.removeAllServer()
//                data?.forEach { itme ->
//                    AngConfigManager.importConfig(nodeModel = itme,"1232132131",null)
//                }
               // AngConfigManager.updateServersCacheNode(data ?: emptyList())
                var selectedIndex = -1
                val nodelModel  = getSelectNode()
                if (nodelModel!=null){
                    data?.forEachIndexed { index, node ->
                        if(node.id == nodelModel.id)
                        {
                            selectedIndex = index
                        }
                    }
                }
                hidLoading()
                data?.let {
                    viewStates = viewStates.copy(
                        dataList = it,
                        selectedIndex=selectedIndex,
                        pageState = PageState.Success(it.isEmpty()))
                }

                //updateMainEvent(MainEvent.IsReqFsh,false)
            }

        }.onFailure {
            hidLoading()
            Log.e("xxx", "onFailure 获取节点线路 接口异常 $it")
            viewStates = viewStates.copy(pageState = PageState.Error(it.message ?: ""))
            //updateMainEvent(MainEvent.IsError,false)
        }

        //homeLazyListState.layoutInfo.totalItemsCount
    }



}


data class NodeViewState(
    val dataList: List<NodeModel> = emptyList(),
    var selectedIndex:Int = -1,
    var updateListAction:Int = -1,
    var expanded:Boolean = false,
    val pageState: PageState = PageState.Loading,
    val listState: LazyListState = LazyListState()
) {
    val size = dataList.size
}

/**
 * 一次性事件
 */
sealed class NodeViewEvent {
    object MsTest : NodeViewEvent()
    object Not : NodeViewEvent()
    data class ErrorMessage(val message: String) : NodeViewEvent()
}

sealed class  NodeViewAction {
    object UserNode : NodeViewAction()
    data class NodeRefresh(val isRefresh: Boolean) : NodeViewAction()
    data class UpdateSelect(val selectedIndex: Int) : NodeViewAction()
    data class UpdateExpanded(val expanded: Boolean) : NodeViewAction()
}
