package com.vpn.fastestvpnservice.utils

import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.AsyncTask
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.vpn.fastestvpnservice.application.App
import com.vpn.fastestvpnservice.constants.AppEnum
import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
import com.vpn.fastestvpnservice.viewmodels.HomeViewModel
import com.wireguard.android.backend.Backend
import com.wireguard.android.backend.GoBackend
import com.wireguard.android.backend.Tunnel
import com.wireguard.config.Config
import com.wireguard.config.InetEndpoint
import com.wireguard.config.InetNetwork
import com.wireguard.config.Interface
import com.wireguard.config.Peer
import wireguard.WgTunnel
import java.util.SortedSet

class WireGuardConnection {

    var context: Context
    var activity: ComponentActivity
    var basePreferenceHelper: BasePreferenceHelper
    var homeViewModel: HomeViewModel

    var backend: Backend? = null
    final var peerBuilder = Peer.Builder()
    final var tunnel: Tunnel = WgTunnel()
    lateinit var tunnelStatus: Tunnel.State

    constructor(context: Context, activity: ComponentActivity, homeViewModel: HomeViewModel) {
        this.context = context
        this.activity = activity
        this.basePreferenceHelper = BasePreferenceHelper(context)
        this.backend = GoBackend(context)
        this.homeViewModel = homeViewModel
    }

    fun startVpn() {
        Log.d("test_wg", "start vpn")

        if (basePreferenceHelper.getProtocol().title.toLowerCase()
                .contentEquals(AppEnum.WG_PROTOCOL.key.toLowerCase())
        ) {
            Log.d("test_wg", "WG protocol")
            vpnWireGuardPermission(true)
        }
    }

    fun vpnWireGuardPermission(isUp: Boolean) {

        Log.d("test_wg", "vpnWireGuardPermission = $isUp")

        if (App.backend != null)
        {
            App.backend?.runningTunnelNames
        }
        else {
            val back = GoBackend(context)
            App.setBackend(back)
            App.backend = App.getBackend()
        }

        try{
            Log.d("test_wg", "try = $isUp")
            val intentPrepare: Intent = GoBackend.VpnService.prepare(context)
            if (intentPrepare != null) {
                activity.startActivityForResult(intentPrepare, 552)
            }
        }catch (e :Exception){
            Log.d("test_wg", "catch = $isUp")
            vpnWireGuard(isUp)
        }
    }


    fun vpnWireGuard(isUp: Boolean) {
        Log.d("test_wg", "vpnWireGuard = $isUp")

        val interfaceBuilder: Interface.Builder? = Interface.Builder()
        // WireGuard

        AsyncTask.execute {
            try {
                if (isUp) {
                    App.tunnelStatus = Tunnel.State.UP
                    homeViewModel.setConnectState(true)
                    Log.d("test_wg", "tunnelStatus if = ${App.tunnelStatus}")

                } else {
                    App.tunnelStatus = Tunnel.State.DOWN
                    homeViewModel.setConnectState(false)
                    Log.d("test_wg", "tunnelStatus else = ${App.tunnelStatus}")
                }

                val server = basePreferenceHelper.getServerObject()
                val wireguard = basePreferenceHelper.getWireGuard()
                Log.d("test_wg", "server = ${server?.server_name}, dns = ${server?.dns}, wg.ip = ${wireguard?.ip}, wg.key = ${wireguard?.key}")

                Log.d("test_wg", "${App.backend} ${App.getTunnel()} ${App.tunnelStatus} ${App.peerBuilder}")
                App.backend?.setState(
                    App.getTunnel(), App.tunnelStatus, Config.Builder().setInterface(
                        interfaceBuilder!!.addAddress(InetNetwork.parse(basePreferenceHelper.getWireGuard()?.ip + "/32"))
                            .parsePrivateKey(basePreferenceHelper.getWireGuard()?.key)
                            .parseDnsServers("10.8.8.8")
                            .build()
                    ).addPeer(
                        App.peerBuilder.addAllowedIp(InetNetwork.parse("0.0.0.0/0"))
                            .setEndpoint(InetEndpoint.parse(basePreferenceHelper.getServerObject()?.dns + ":51820"))
                            .parsePublicKey(basePreferenceHelper.getServerObject()?.wg_key).build()
                    ).build()
                )

//                    try {
//                        App.backend?.runningTunnelNames
//                    } catch (e: Exception) {
//                        val back = GoBackend(context)
//                        App.setBackend(back)
//                        App.backend = App.getBackend()
//                    }
//                homeViewModel.setConnectState(true)

            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
        }
    }

    fun stopVpn() {
        Log.d("test_wg", "stop vpn")
        if (basePreferenceHelper.getProtocol().title.toLowerCase()
                .contentEquals(AppEnum.WG_PROTOCOL.key.toLowerCase())
        )
        {
            vpnWireGuardPermission(false)
        }
    }

    fun isVPNConnected(): Boolean {
        try {
            val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val networks = cm.allNetworks
            for (network in networks) {
                val caps = cm.getNetworkCapabilities(network)

                if (caps!!.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) return true
            }
            return false
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

}