package com.lanyun.wanglaotou.viewModel

import android.util.Log
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.*
import com.lanyun.common.base.BaseViewModel
import com.lanyun.common.baseDate.updateMainEvent
import com.lanyun.common.ext.requestNoCheck

import com.lanyun.common.model.MainEvent
import com.lanyun.net.ext.*
import com.lanyun.wanglaotou.App
import com.lanyun.wanglaotou.AppConfig
import com.lanyun.wanglaotou.R
import com.lanyun.wanglaotou.dao.ServersCache
import com.lanyun.wanglaotou.extension.toast
import com.lanyun.wanglaotou.model.NodeModel
import com.lanyun.wanglaotou.model.UserModel
import com.lanyun.wanglaotou.model.UserSubModel
import com.lanyun.wanglaotou.model.VersionModel
import com.lanyun.wanglaotou.public.PageState
import com.lanyun.wanglaotou.repo.HomeRepo
import com.lanyun.wanglaotou.util.*
import com.tencent.mmkv.MMKV
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.receiveAsFlow

class HomeViewModel : BaseViewModel()  {
    private val tcpingTestScope by lazy { CoroutineScope(Dispatchers.IO) }
    private val mainStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
    val menuItemSelected by lazy { MutableLiveData<Int>() }
    var viewStates by mutableStateOf(HomeViewState())
        private set
    private val _viewEvents = Channel<HomeViewEvent>(Channel.BUFFERED)
    val viewEvents = _viewEvents.receiveAsFlow()

    init {
//        val viewModel1 = ViewModelProvider(this).get(MainViewModel::class.java)
//        viewModel1.menuItemSelected.observe(this, onChanged = {
//            menuItemSelected.value = it
//        })
        dispatch(HomeViewAction.UserSubData)
    }

    fun dispatch(action: HomeViewAction) {
        when (action) {
            is HomeViewAction.UserSubData -> {
                if (isLogin())
                    getSubUserInfo()
            }
            is HomeViewAction.UserNode -> getNodes()
            is HomeViewAction.NodeRefresh -> {
                if (isLogin())
                    getNodes(true)
            }
            is HomeViewAction.UpdateSelect ->{
                updateSelect(action.selectedIndex)
            }
            is HomeViewAction.VerionUpdate ->{
                getAppVersion()
            }
            is HomeViewAction.UserData -> getUserInfo()
            is HomeViewAction.updateSubModel -> getReSubUserInfo()
        }
    }
    private fun updateSelect(selectedIndex: Int) {
        viewStates = viewStates.copy(selectedIndex = selectedIndex)

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

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

    fun selectNode(serversCache: ServersCache){
        MmkvManager.encodeSelectServer(serversCache.nodeModel)
        Log.d(AppConfig.ANG_PACKAGE, "startV2rayPoint---guid${serversCache.guid}---config${serversCache.config.remarks}")
        mainStorage?.encode(MmkvManager.KEY_SELECTED_SERVER, serversCache.guid)
        //updateMainEvent(MainEvent.MainNodeUpdate,true)
    }

    fun updateLegacyItme(){
        val serversCache = AngConfigManager.serversCache
        tcpingTestScope.coroutineContext[Job]?.cancelChildren()
        for (item in serversCache) {
            tcpingTestScope.launch {
                viewStates = viewStates.copy(updateListAction = getPositionGuid(item.guid))
            }
        }

    }


    fun testAllRealPing() {
        MessageUtil.sendMsg2TestService(App.CONTEXT, AppConfig.MSG_MEASURE_CONFIG_CANCEL, "")
        MmkvManager.clearAllTestDelayResults()
        val serversCache = AngConfigManager.serversCache
        viewStates = viewStates.copy(updateListAction = -1)
        App.CONTEXT.toast(R.string.connection_test_testing)
        viewModelScope.launch(Dispatchers.Default) { // without Dispatchers.Default viewModelScope will launch in main thread
            for (item in serversCache) {

                val config = V2rayConfigUtil.getV2rayConfig(App.CONTEXT, item.guid)
                if (config.status) {
                    MessageUtil.sendMsg2TestService(App.CONTEXT, AppConfig.MSG_MEASURE_CONFIG, Pair(item.guid, config.content))
                }
            }
        }
    }

    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 = getPositionGuid(item.guid))
                }
            }
        }

    }

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


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

    private fun getUserInfo() = serverAwait {
        HomeRepo.getUserInfo().serverData().onSuccess {
            onBizError { code, error_message ->
                viewStates = viewStates.copy(pageState = PageState.Error(error_message ?: ""))
            }
            onBizOK<UserModel> { code, data, error_message ->
                data?.let {
                    MmkvManager.encodeUserinfo(it)
                    viewStates = viewStates.copy(pageState = PageState.Success(it.email.isEmpty()))

                }
                updateMainEvent(MainEvent.MainGetUpdate)
            }
        }.onFailure {
            viewStates = viewStates.copy(pageState = PageState.Error(it.message ?: ""))
        }
    }

    private fun getAppVersion() = serverAwait {
        viewStates = viewStates.copy(
            version = "正在检查更新.."
        )

        val version = VersionUtil.getVersionName(App.CONTEXT) ?:""

        HomeRepo.getAppVersion("android", version ).serverData().onSuccess {
            onBizError { code, error_message ->
                viewStates = viewStates.copy(
                    version = "$error_message,$version"
                )
            }
            onBizOK<VersionModel> { code, data, error_message ->
                data?.let {
                    viewStates = viewStates.copy(
                        versionData = it,
                        version = "版本号:${version},$error_message"
                    )
                    if (it.isUpdate == 1){

                        updateMainEvent(MainEvent.MainAppUpdate)
                    } else {

                        updateMainEvent(MainEvent.IsReqFsh)
                    }
                }
            }
        }.onFailure {
            viewStates = viewStates.copy(
                version = "检查更新失败,$version"
            )
        }
    }

    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.removeCache()
              //  AngConfigManager.updateServersCacheNode(data ?: emptyList())
                var selectedIndex = -1
                val nodelModel  = getSelectNode()
                if (nodelModel!=null){
                    data?.forEachIndexed { index, node ->
                        if(node.id == nodelModel.id)
                        {
                            selectedIndex = index
                        }

                        viewStates.userSubInfoData?.let { userSub ->
                            AngConfigManager.importConfig(nodeModel = node,userSub.uuid,null,true)
                        }

                    }
                } else {
                    data?.forEachIndexed { index, node ->
                        viewStates.userSubInfoData?.let { userSub ->
                            AngConfigManager.importConfig(nodeModel = node,userSub.uuid,null,true)
                        }

                    }
                }
                hidLoading()
                viewStates = viewStates.copy(
                    dataList = AngConfigManager.serversCache,
                    userSubInfoData= viewStates.userSubInfoData,
                    selectedIndex=selectedIndex,
                    pageState = PageState.Success(AngConfigManager.serversCache.isEmpty())
                )
                updateMainEvent(MainEvent.MainGetUpdate)
            }

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

        //homeLazyListState.layoutInfo.totalItemsCount
    }


    fun getReSubUserInfo() = serverAwait {
        showLoading()
        //viewStates = viewStates.copy(pageState = PageState.LoadingDialog)
        HomeRepo.getUserSubInfo().serverData().onSuccess {
            onBizError { code, error_message ->
                hidLoading()
                updateMainEvent(MainEvent.IsError,false)
                viewStates = viewStates.copy(pageState = PageState.Error(error_message ?: ""))
                Log.e("xxx", "getUserInfo onFailure 获取节点线路 接口异常 $error_message")
            }
            onBizOK<UserSubModel>  { code, data, error_message ->
                data?.let {
                    MmkvManager.encodeSubUserinfo(it)
                    viewStates = viewStates.copy(
                        userSubInfoData= it,
                        pageState = PageState.Success(it.email.isEmpty())
                    )
                }

                updateMainEvent(MainEvent.IsReqFsh)


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

    fun getSubUserInfo() = serverAwait {
        showLoading()
        viewStates = viewStates.copy(pageState = PageState.LoadingDialog)
        HomeRepo.getUserSubInfo().serverData().onSuccess {
            onBizError { code, error_message ->
                hidLoading()
                updateMainEvent(MainEvent.IsError,false)
                viewStates = viewStates.copy(pageState = PageState.Error(error_message ?: ""))
                Log.e("xxx", "getUserInfo onFailure 获取节点线路 接口异常 $error_message")
            }
            onBizOK<UserSubModel>  { code, data, error_message ->
                data?.let {
                    MmkvManager.encodeSubUserinfo(it)
                    viewStates = viewStates.copy(
                        userSubInfoData= it,
                        )
                }

                updateMainEvent(MainEvent.MainNodeUpdate)


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



}

data class HomeViewState(
    val dataList: List<ServersCache> = emptyList(),
    val userSubInfoData: UserSubModel? = null,
    val versionData: VersionModel? = null,
    var selectedIndex:Int = -1,
    var updateListAction:Int = -1,
    val pageState: PageState = PageState.Loading,
    val listState: LazyListState = LazyListState(),
    val version:String = "正在检查更新.."
) {
    val size = dataList.size
}

/**
 * 一次性事件
 */
sealed class HomeViewEvent {
    object UserNode : HomeViewEvent()
    object UserSubData : HomeViewEvent()
    object TcpPing : HomeViewEvent()
    data class ErrorMessage(val message: String) : HomeViewEvent()
}
sealed class  HomeViewAction {
    object UserSubData : HomeViewAction()
    object UserData : HomeViewAction()
    object UserNode : HomeViewAction()
    object updateSubModel : HomeViewAction()
    object NodeRefresh: HomeViewAction()
    object VerionUpdate: HomeViewAction()
    data class UpdateSelect(val selectedIndex: Int) : HomeViewAction()
}