package hanson.xyz.vpnhotspotmod

import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.core.content.FileProvider
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import hanson.xyz.vpnhotspotmod.App.Companion.app
import hanson.xyz.vpnhotspotmod.net.TetherOffloadManager
import hanson.xyz.vpnhotspotmod.net.monitor.FallbackUpstreamMonitor
import hanson.xyz.vpnhotspotmod.net.monitor.IpMonitor
import hanson.xyz.vpnhotspotmod.net.monitor.UpstreamMonitor
import hanson.xyz.vpnhotspotmod.net.wifi.WifiDoubleLock
import hanson.xyz.vpnhotspotmod.preference.AutoCompleteNetworkPreferenceDialogFragment
import hanson.xyz.vpnhotspotmod.preference.SharedPreferenceDataStore
import hanson.xyz.vpnhotspotmod.preference.SummaryFallbackProvider
import hanson.xyz.vpnhotspotmod.root.Dump
import hanson.xyz.vpnhotspotmod.root.RootManager
import hanson.xyz.vpnhotspotmod.util.Services
import hanson.xyz.vpnhotspotmod.util.launchUrl
import hanson.xyz.vpnhotspotmod.util.showAllowingStateLoss
import hanson.xyz.vpnhotspotmod.widget.SmartSnackbar
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.PrintWriter
import kotlin.system.exitProcess

class SettingsPreferenceFragment : PreferenceFragmentCompat() {
    private fun Preference.remove() = parent!!.removePreference(this)
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        // handle complicated default value and possible system upgrades
        WifiDoubleLock.mode = WifiDoubleLock.mode
        RoutingManager.masqueradeMode = RoutingManager.masqueradeMode
        IpMonitor.currentMode = IpMonitor.currentMode
        preferenceManager.preferenceDataStore = SharedPreferenceDataStore(app.pref)
        addPreferencesFromResource(R.xml.pref_settings)
        SummaryFallbackProvider(findPreference(UpstreamMonitor.KEY)!!)
        SummaryFallbackProvider(findPreference(FallbackUpstreamMonitor.KEY)!!)
        findPreference<TwoStatePreference>("system.enableTetherOffload")!!.apply {
            isChecked = TetherOffloadManager.enabled
            setOnPreferenceChangeListener { _, newValue ->
                if (TetherOffloadManager.enabled != newValue) viewLifecycleOwner.lifecycleScope.launch {
                    isEnabled = false
                    try {
                        TetherOffloadManager.setEnabled(newValue as Boolean)
                    } catch (_: CancellationException) {
                    } catch (e: Exception) {
                        Timber.w(e)
                        SmartSnackbar.make(e).show()
                    }
                    isChecked = TetherOffloadManager.enabled
                    isEnabled = true
                }
                false
            }
        }
        findPreference<TwoStatePreference>(BootReceiver.KEY)!!.setOnPreferenceChangeListener { _, value ->
            BootReceiver.onUserSettingUpdated(value as Boolean)
            true
        }
        if (Services.p2p == null || !RepeaterService.safeModeConfigurable) {
            val safeMode = findPreference<Preference>(RepeaterService.KEY_SAFE_MODE)!!
            safeMode.remove()
        }
        if (Build.VERSION.SDK_INT < 30) findPreference<Preference>(LocalOnlyHotspotService.KEY_USE_SYSTEM)!!.remove()
        findPreference<Preference>("service.clean")!!.setOnPreferenceClickListener {
            GlobalScope.launch { RoutingManager.clean() }
            true
        }
        findPreference<Preference>(IpMonitor.KEY)!!.setOnPreferenceChangeListener { _, _ ->
            Snackbar.make(requireView(), R.string.settings_restart_required, Snackbar.LENGTH_LONG).apply {
                setAction(R.string.settings_exit_app) {
                    GlobalScope.launch {
                        RoutingManager.clean(false)
                        exitProcess(0)
                    }
                }
            }.show()
            true
        }
        findPreference<Preference>("misc.logcat")!!.setOnPreferenceClickListener {
            GlobalScope.launch(Dispatchers.IO) {
                val context = requireContext()
                val logDir = File(context.cacheDir, "log")
                logDir.mkdir()
                val logFile = File.createTempFile("vpnhotspot-", ".log", logDir)
                logFile.outputStream().use { out ->
                    PrintWriter(out.bufferedWriter()).use { writer ->
                        writer.println("${BuildConfig.VERSION_CODE} is running on API ${Build.VERSION.SDK_INT}\n")
                        writer.flush()
                        try {
                            Runtime.getRuntime().exec(arrayOf("logcat", "-d")).inputStream.use { it.copyTo(out) }
                        } catch (e: IOException) {
                            Timber.w(e)
                            e.printStackTrace(writer)
                        }
                        writer.println()
                    }
                }
                try {
                    RootManager.use {
                        it.execute(Dump(logFile.absolutePath))
                    }
                } catch (e: Exception) {
                    if (e !is CancellationException) Timber.w(e)
                    PrintWriter(FileOutputStream(logFile, true)).use { e.printStackTrace(it) }
                }
                context.startActivity(Intent.createChooser(Intent(Intent.ACTION_SEND)
                        .setType("text/x-log")
                        .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                        .putExtra(Intent.EXTRA_STREAM,
                                FileProvider.getUriForFile(context, "hanson.xyz.vpnhotspotmod.log", logFile)),
                        context.getString(androidx.appcompat.R.string.abc_shareactionprovider_share_with)))
            }
            true
        }
        findPreference<Preference>("misc.source")!!.setOnPreferenceClickListener {
            requireContext().launchUrl("https://github.com/Mygod/VPNHotspot/blob/master/README.md")
            true
        }
        findPreference<Preference>("misc.donate")!!.setOnPreferenceClickListener {
            EBegFragment().showAllowingStateLoss(parentFragmentManager, "EBegFragment")
            true
        }
        findPreference<Preference>("misc.licenses")!!.setOnPreferenceClickListener {
            startActivity(Intent(context, OssLicensesMenuActivity::class.java))
            true
        }
    }

    override fun onDisplayPreferenceDialog(preference: Preference) = when (preference.key) {
        UpstreamMonitor.KEY, FallbackUpstreamMonitor.KEY ->
            AutoCompleteNetworkPreferenceDialogFragment().apply {
                setArguments(preference.key)
                setTargetFragment(this@SettingsPreferenceFragment, 0)
            }.showAllowingStateLoss(parentFragmentManager, preference.key)
        else -> super.onDisplayPreferenceDialog(preference)
    }
}
