package hanson.xyz.vpnhotspotmod

import android.os.Bundle
import android.view.MenuItem
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import hanson.xyz.vpnhotspotmod.client.ClientViewModel
import hanson.xyz.vpnhotspotmod.client.ClientsFragment
import hanson.xyz.vpnhotspotmod.databinding.ActivityMainBinding
import hanson.xyz.vpnhotspotmod.manage.TetheringFragment
import hanson.xyz.vpnhotspotmod.net.IpNeighbour
import hanson.xyz.vpnhotspotmod.net.wifi.WifiDoubleLock
import hanson.xyz.vpnhotspotmod.util.AppUpdate
import hanson.xyz.vpnhotspotmod.util.ServiceForegroundConnector
import hanson.xyz.vpnhotspotmod.util.Services
import hanson.xyz.vpnhotspotmod.util.UpdateChecker
import hanson.xyz.vpnhotspotmod.widget.SmartSnackbar
import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.navigation.NavigationBarView
import kotlinx.coroutines.launch
import timber.log.Timber
import java.net.Inet4Address
import java.util.concurrent.CancellationException

class MainActivity : AppCompatActivity(), NavigationBarView.OnItemSelectedListener {
    lateinit var binding: ActivityMainBinding
    private lateinit var updateItem: MenuItem
    private lateinit var updateBadge: BadgeDrawable

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        WindowCompat.setDecorFitsSystemWindows(window, false)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content)) { view, insets ->
            val statusBarInsets = insets.getInsets(WindowInsetsCompat.Type.statusBars())
            view.setPadding(statusBarInsets.left, statusBarInsets.top, statusBarInsets.right, statusBarInsets.bottom)
            WindowInsetsCompat.Builder(insets).apply {
                setInsets(WindowInsetsCompat.Type.statusBars(), Insets.NONE)
            }.build()
        }
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.navigation.setOnItemSelectedListener(this)
        val badge = binding.navigation.getOrCreateBadge(R.id.navigation_clients).apply {
            backgroundColor = resources.getColor(R.color.colorSecondary, theme)
            badgeTextColor = resources.getColor(androidx.appcompat.R.color.primary_text_default_material_light, theme)
        }
        updateItem = binding.navigation.menu.findItem(R.id.navigation_update)
        updateItem.isCheckable = false
        updateBadge = binding.navigation.getOrCreateBadge(R.id.navigation_update).apply {
            backgroundColor = resources.getColor(R.color.colorSecondary, theme)
            badgeTextColor = resources.getColor(androidx.appcompat.R.color.primary_text_default_material_light, theme)
        }
        if (savedInstanceState == null) displayFragment(TetheringFragment())
        val model by viewModels<ClientViewModel>()
        lifecycle.addObserver(model)
        if (Services.p2p != null) ServiceForegroundConnector(this, model, RepeaterService::class)
        model.clients.observe(this) { clients ->
            val count = clients.count {
                it.ip.any { (ip, state) -> ip is Inet4Address && state == IpNeighbour.State.VALID }
            }
            badge.isVisible = count > 0
            badge.number = count
        }
        SmartSnackbar.Register(binding.fragmentHolder)
        WifiDoubleLock.ActivityListener(this)
        lifecycleScope.launch {
            BootReceiver.startIfEnabled()
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                onAppUpdateAvailable(null)
                try {
                    UpdateChecker.check().collect(this@MainActivity::onAppUpdateAvailable)
                } catch (_: CancellationException) {
                } catch (e: AppUpdate.IgnoredException) {
                    Timber.d(e)
                } catch (e: Exception) {
                    Timber.w(e)
                    SmartSnackbar.make(e).show()
                }
            }
        }
    }

    private var lastUpdate: AppUpdate? = null
    private fun onAppUpdateAvailable(update: AppUpdate?) {
        lastUpdate = update
        updateItem.isVisible = update != null
        if (update == null) {
            updateItem.isEnabled = false
            return
        }
        updateItem.isEnabled = update.downloaded != false
        updateItem.setIcon(when (update.downloaded) {
            null -> R.drawable.ic_action_update
            false -> R.drawable.ic_file_downloading
            true -> R.drawable.ic_action_autorenew
        })
        updateItem.title = update.message ?: getText(R.string.title_update)
        updateBadge.isVisible = when (val days = update.stalenessDays) {
            null -> false
            else -> {
                if (days > 0) updateBadge.number = days else updateBadge.clearNumber()
                true
            }
        }
    }

    override fun onNavigationItemSelected(item: MenuItem) = when (item.itemId) {
        R.id.navigation_clients -> {
            displayFragment(ClientsFragment())
            true
        }
        R.id.navigation_tethering -> {
            displayFragment(TetheringFragment())
            true
        }
        R.id.navigation_settings -> {
            displayFragment(SettingsPreferenceFragment())
            true
        }
        R.id.navigation_update -> {
            lastUpdate!!.updateForResult(this, 1)
            false
        }
        else -> false
    }

    private fun displayFragment(fragment: Fragment) =
            supportFragmentManager.beginTransaction().replace(R.id.fragmentHolder, fragment).commitAllowingStateLoss()
}
