package com.vpn.fastestvpnservice.viewmodels

import android.content.Context
import android.os.Looper
import android.util.Log
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.stealthcopter.networktools.Ping
import com.stealthcopter.networktools.ping.PingResult
import com.stealthcopter.networktools.ping.PingStats
import com.vpn.fastestvpnservice.beans.Server
import com.vpn.fastestvpnservice.beans.ServerData
import com.vpn.fastestvpnservice.beans.ServerResponse
import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
import com.vpn.fastestvpnservice.helpers.UIHelper
import com.vpn.fastestvpnservice.retrofit.RetrofitNetworkHandling
import com.vpn.fastestvpnservice.retrofit.WebServiceFactory
import retrofit2.Call

class ServerListViewModel(context: Context): ViewModel() {

    private var preferencesHelper = BasePreferenceHelper(context)

    val mutableLiveData = MutableLiveData<List<ServerData>>()
    val mutableLiveDataFavourite = MutableLiveData<List<Server>>()
    val mutableLiveDataFavUnFav = MutableLiveData<ServerResponse?>()

    var _mutableLiveDataPing = MutableLiveData<Int?>(0)
    var liveDataPing: LiveData<Int?> = _mutableLiveDataPing

    var _mutableLiveDataPagerIndex = MutableLiveData<Int>(0)
    var liveDataPagerIndex: LiveData<Int> = _mutableLiveDataPagerIndex

    var _mutableLiveDataGetFavList = MutableLiveData<ArrayList<Server>>(getFavList())
    var liveDataGetFavList: LiveData<ArrayList<Server>> = _mutableLiveDataGetFavList

    var _mutableLiveDataGetServers = MutableLiveData<ArrayList<Server>>()
    var liveDataGetServers: LiveData<ArrayList<Server>> = _mutableLiveDataGetServers

    var _mutableLiveDataGetServerData = MutableLiveData<ArrayList<ServerData>>(getServerData())
    var liveDataGetServerData: LiveData<ArrayList<ServerData>> = _mutableLiveDataGetServerData

//    init {
//        preferencesHelper = BasePreferenceHelper(context)
//    }

    fun setPagerIndex(index: Int) {
        _mutableLiveDataPagerIndex.value = index
    }

    fun calculatePing(server: Server, onPingResult: (Int) -> Unit) {
        Ping.onAddress(server.ip as String).setTimeOutMillis(1000).doPing(
            object : Ping.PingListener{
                override fun onResult(pingResult: PingResult?) {
                    android.os.Handler(Looper.getMainLooper()).post {
                        val ping = pingResult?.timeTaken?.toInt()!!
                        onPingResult(ping)
                        Log.d("test_ping", "ping[0] = $ping")
                    }
                }

                override fun onError(e: java.lang.Exception?) {}
                override fun onFinished(pingStats: PingStats?) {}
            }
        )
    }

    fun filterServersByISO(serverlist: ArrayList<Server>): ArrayList<Server> {

        serverlist.forEachIndexed { index, server ->
            Log.d("serverlist_test", server.server_name + " , " + server.country)
        }

        serverlist.sortWith(Comparator { s1, s2 ->
            return@Comparator s1.country_sort.compareTo(s2.country_sort)
        })

        serverlist.forEachIndexed { index, server ->
            Log.d("serverlist_test 2", server.server_name + " , " + server.country)
        }

        var serverprotocol = serverlist.filter {
            it.protocol.equals(preferencesHelper.getProtocol().title, ignoreCase = true)
        }

        serverprotocol.forEachIndexed { index, server ->
            Log.d("serverlist_test p", server.server_name + " , " + server.country)
        }

        var distinctBy: List<Server>
        distinctBy = serverprotocol.distinctBy {
            it.iso
        }

        distinctBy.forEachIndexed { index, server ->
            Log.d("serverlist_test d", server.server_name + " , " + server.country)
        }

        serverprotocol.groupBy(Server::country).mapValues { entry ->

            for ((index, value) in distinctBy.withIndex()) {

                if (entry.key == value.country) {
                    distinctBy.get(index).totalServers = entry.value.sumBy { it.totalServers }
//                    distinctBy.get(index).totalServers = 1


                    var total_enables = entry.value.sumBy { it.enable }

                    println("--testing "+entry.value.size +" : "+total_enables+" : "+value.country)

                    entry.value.forEachIndexed { indexs, server ->
                        Log.d("test_country_servers",server.country + " " + server.server_name.toString())
                    }

                    distinctBy.get(index).countryServers = entry.value

                    value.countryServers?.forEachIndexed { indexs1, serverInfo ->
                        calculatePing(serverInfo) {
                            serverInfo.ping = it
                            Log.d("test_return_ping","ISO=> " + serverInfo.server_name + serverInfo.ping)
                        }
                    }

                    if (total_enables >= 1) {
                        distinctBy.get(index).enableServers = 1
                    } else {
                        distinctBy.get(index).enableServers = 0
                    }
                }

            }
        }

        distinctBy.forEachIndexed { index, server ->
            Log.d("serverlist_test d 2", server.server_name + " , " + server.country + " , " + server.totalServers)
        }

        return (distinctBy as ArrayList<Server>)
    }

    fun filterServersByISOTV(serverlist: ArrayList<Server>): ArrayList<Server> {

        serverlist.forEachIndexed { index, server ->
            Log.d("serverlist test", server.server_name + " , " + server.country)
        }

        serverlist.sortWith(Comparator { s1, s2 ->
            return@Comparator s1.country_sort.compareTo(s2.country_sort)
        })

        serverlist.forEachIndexed { index, server ->
            Log.d("serverlist 2 test 2", server.server_name + " , " + server.country)
        }

        var serverprotocol = serverlist.filter {
            it.protocol.equals(preferencesHelper.getProtocol().title, ignoreCase = true)
        }

        serverprotocol.forEachIndexed { index, server ->
            Log.d("serverprotocol test", server.server_name + " , " + server.country)
        }

        var distinctBy: List<Server>
        distinctBy = serverprotocol.distinctBy {
            it.iso
        }

        distinctBy.forEachIndexed { index, server ->
            Log.d("distinctBy test", server.server_name + " , " + server.country)
        }

        serverprotocol.groupBy(Server::country).mapValues { entry ->

            for ((index, value) in distinctBy.withIndex()) {

                if (entry.key == value.country) {
                    distinctBy.get(index).totalServers = entry.value.sumBy { it.totalServers }

                    var total_enables = entry.value.sumBy { it.enable }

                    println("--testing "+entry.value.size +" : "+total_enables+" : "+value.country)

                    if (total_enables >= 1) {
                        distinctBy.get(index).enableServers = 1
                    } else {
                        distinctBy.get(index).enableServers = 0
                    }
                }

            }
        }

        distinctBy.forEachIndexed { index, server ->
            Log.d("distinctBy_test_enable", server.server_name + " , " + server.enable)
        }

        val enabledServer = distinctBy.filter {
            it.enable == 1
        }

        return (enabledServer as ArrayList<Server>)
    }


    // By Khubaib...

    fun filterServersAllCategory(serverlist: ArrayList<Server>): ArrayList<Server> {
        serverlist.sortWith(Comparator { s1, s2 ->
            return@Comparator s1.country_sort.compareTo(s2.country_sort)
        })

        val serverProtocol = serverlist.filter {
            it.protocol.equals(preferencesHelper.getProtocol().title, ignoreCase = true)
        }

        val distinctBy: List<Server> = serverProtocol.distinctBy {
            it.server_name
        }

        val data = distinctBy as ArrayList<Server>

        data.sortBy {
            it.server_name
        }

        data.forEachIndexed { index, server ->
            calculatePing(server) {
                server.ping = it
            }
        }
//        serverProtocol.groupBy(Server::country).mapValues { entry ->
//            for ((index, value) in distinctBy.withIndex()) {
//                if (entry.key == value.country) {
//                    distinctBy.get(index).totalServers = entry.value.sumBy { it.totalServers }
//                }
//            }
//        }

        return (data)
    }

    fun filterServersWithTvCountries(serverlist: ArrayList<Server>): ArrayList<Server> {
        serverlist.sortWith(Comparator { s1, s2 ->
            return@Comparator s1.country_sort.compareTo(s2.country_sort)
        })

        val serverprotocol = serverlist.filter {
            it.protocol.equals(preferencesHelper.getProtocol().title, ignoreCase = true)
        }

        val distinctBy: List<Server> = serverprotocol.distinctBy {
            it.server_name
        }

        serverprotocol.groupBy(Server::country).mapValues { entry ->
            for ((index, value) in distinctBy.withIndex()) {
                if (entry.key == value.country) {
                    distinctBy.get(index).totalServers = entry.value.sumBy { it.totalServers }
                }
            }
        }

        val enabledServer = distinctBy.filter {
            it.enable == 1
        }

        return (enabledServer as ArrayList<Server>)
    }

    fun filterServersByStreamingServers(serverlist: ArrayList<Server>): ArrayList<Server> {

        serverlist.sortWith(Comparator { s1, s2 ->
            return@Comparator s1.country_sort.compareTo(s2.country_sort)
        })

        var serverprotocol = serverlist.filter {
            it.protocol.equals(preferencesHelper.getProtocol().title, ignoreCase = true)
        }

        var distinctBy: List<Server>
        distinctBy = serverprotocol.distinctBy {
            it.server_name
        }

        Log.d("streaming_servers t", distinctBy.size.toString())


        serverprotocol.groupBy(Server::server_name).mapValues { entry ->
            for ((index, value) in distinctBy.withIndex()) {
                if (entry.key == value.server_name) {
//                    distinctBy.get(index).totalServers = entry.value.sumBy { it.totalServers }
                    distinctBy.get(index).totalServers = 1

                    distinctBy.get(index).countryServers = entry.value

//                    calculatePing(value) {
//                        distinctBy.get(index).ping = it
//                        Log.d("test_return_ping", "value => ${value.server_name} ${value.ping}")
//                    }

                    value.countryServers?.forEachIndexed { indexs1, serverInfo ->
                        calculatePing(serverInfo) {
                            serverInfo.ping = it
                            Log.d("test_return_ping", "SS=> " +serverInfo.server_name + serverInfo.ping)
                        }
                    }
                }
            }
        }

        Log.d("streaming_servers t", distinctBy.size.toString())
        return (distinctBy as ArrayList<Server>)
    }

    fun filterServersByStreamingServersTV(serverlist: ArrayList<Server>): ArrayList<Server> {

        serverlist.sortWith(Comparator { s1, s2 ->
            return@Comparator s1.country_sort.compareTo(s2.country_sort)
        })

        var serverprotocol = serverlist.filter {
            it.protocol.equals(preferencesHelper.getProtocol().title, ignoreCase = true)
        }

        var distinctBy: List<Server>
        distinctBy = serverprotocol.distinctBy {
            it.server_name
        }

        serverprotocol.groupBy(Server::country).mapValues { entry ->
            for ((index, value) in distinctBy.withIndex()) {
                if (entry.key == value.country) {
                    distinctBy.get(index).totalServers = entry.value.sumBy { it.totalServers }
                }
            }
        }

        val enabledServer = distinctBy.filter {
            it.enable == 1
        }

        return (enabledServer as ArrayList<Server>)
    }

    fun filterServerByConnectionCount(serverlist: ArrayList<Server>): Server {
        //sort start//
        serverlist.sortWith(Comparator { s1, s2 ->
            return@Comparator s1.country_sort.compareTo(s2.country_sort)
        })

        var temp = serverlist.filter {
            it.protocol.equals(preferencesHelper.getProtocol().title, ignoreCase = true)
        }

        val distinctBy = temp.sortedBy {
            it.connection_count
        }.distinctBy {
            it.iso
        }

        distinctBy.forEachIndexed { index, server ->
            Log.d("test server cc", server.server_name.toString() + server.country)
        }

        return distinctBy[0]
    }

    fun getFilteredServerListByConnectionCount(serverList: ArrayList<Server>, serverObj: Server): Server {
        val protocol = preferencesHelper.getProtocol().title
        var tempList = ArrayList<Server>()
        var tempList2 = ArrayList<Server>()

        for (i in serverList.indices) {
            var obj = serverList[i]

            if (obj.iso == serverObj.iso && protocol.equals(obj.protocol, ignoreCase = true)) {
                tempList.add(obj)
            }
        }

        for (server in tempList)
        {
            if (serverObj.enableServers == 1)
            {
                if (server.enable == 1)
                {
                    tempList2.add(server)
                }
            }
            else{
                if (server.enable == 0){
                    tempList2.add(server)
                }
            }

        }

        tempList2.sortBy {
            it.connection_count
        }

        tempList2.forEach {
            Log.d("tempList2", it.server_name + " : " + it.connection_count)
        }

        return tempList2[0]
    }

    fun favAndUnFav(server: Server) {
//        updateFavServer(server)
        WebServiceFactory.getInstance().setFavUnfav("${server.id}")
            .enqueue(RetrofitNetworkHandling<Any>(object :
                RetrofitNetworkHandling.ResponseCallback<Any> {
                override fun onSuccess(call: Call<Any>?, response: Any?) {
                    try {
                        Log.d("test_api_response","Response favAndUnFav = " + response.toString())
                        val gson = Gson()
                        val jsonString = gson.toJson(response)
                        val type = object : TypeToken<ServerResponse>() {}.type
                        val data = gson.fromJson<ServerResponse>(jsonString, type)
                        Log.d("test_api_response","favAndUnFav = " + response.toString())

                        if (data.error == 0)
                        {
                            mutableLiveDataFavUnFav.value = data

                        UIHelper.showToast(data.message)
                        }
                        else {
                            mutableLiveDataFavUnFav.value = null
                        }
                    } catch (ex: Exception) {
                        Log.d("test_api_response","favAndUnFav catch = " + response.toString())

                    }
                }

                override fun onFail(call: Call<Any>?, response: Any?) {
                    mutableLiveDataFavUnFav.value = null
                }

                override fun onError(call: Call<Any>?, response: Any?) {
                    mutableLiveDataFavUnFav.value = null
                }

            }))

    }

    fun getFavList(): ArrayList<Server> {
        val tempList = ArrayList<Server>()

        preferencesHelper.getServerData().let {
            it.forEach {
                tempList.addAll(it.servers?.filter {
                    it.isFavourited == true
                }!!)
            }
        }

        tempList.forEachIndexed { index, server ->
            calculatePing(server) {
                server.ping = it
            }
        }

        Log.d("test_server favList", "size of favlist = ${tempList.size}")
        return tempList
    }

    fun getServerData(): ArrayList<ServerData> {
        return preferencesHelper.getServerData()
    }
    fun updateFavServer(server: Server) {
        server.isFavourited = server.isFavourited != true
        val serverData = preferencesHelper.getServerData()

        serverData.forEachIndexed { i, serverDataList ->
            serverDataList.servers?.let {serverList ->
                serverList.forEachIndexed { index, obj ->
                    if (obj.id == server.id) {
                        Log.d("test_serverData_Fav","if => index[$i]:: obj.id ${obj.id} , server = ${server.server_name}")
//                        obj.isFavourited = obj.isFavourited != true
                        serverList.set(index, server)
                    }
                }
            }
        }

//        serverData.forEachIndexed { i, serverDataList ->
//            serverDataList.servers?.let {serverList ->
//                serverList.forEachIndexed { index, obj ->
//                    if (obj.id == server.id) {
//                        Log.d("test_serverData_Fav","if => index[$i]:: obj.id ${obj.id} , server_id = ${server.id}")
//                        obj.isFavourited = server.isFavourited
//                        serverList[index] = obj
//                    }
//                }
//            }
//        }

        preferencesHelper.saveServerData(serverData)
    }

}

//serverData.let {
//            it.forEach {serverDataList ->
//                Log.d("test_serverData_Fav","data = " + serverDataList.name)
//
//                serverDataList.servers?.let { serversList ->
//                    serversList.forEachIndexed { index, obj ->
//                        if (obj.id == server.id){
//                            obj.isFavourited = server.isFavourited
//                            it.set(index, serverDataList)
//                        }
//                    }
//                }
//            }
//        }