package com.sshproxy.vpn

import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.sshproxy.vpn.data.AppInfo
import com.sshproxy.vpn.data.InstalledAppsProvider
import com.sshproxy.vpn.databinding.ActivityAppExclusionBinding
import com.sshproxy.vpn.ui.AppExclusionAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class AppExclusionActivity : AppCompatActivity() {

    private lateinit var binding: ActivityAppExclusionBinding
    private lateinit var prefs: com.sshproxy.vpn.data.PrefsRepository
    private lateinit var adapter: AppExclusionAdapter

    private var allApps: List<AppInfo> = emptyList()
    private var excludedPackages: Set<String> = emptySet()
    private var includeSystemApps = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityAppExclusionBinding.inflate(layoutInflater)
        setContentView(binding.root)

        prefs = (application as TunnelApplication).prefs
        excludedPackages = prefs.getExcludedPackages()
        includeSystemApps = savedInstanceState?.getBoolean(KEY_INCLUDE_SYSTEM, false) ?: false

        setSupportActionBar(binding.toolbar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        supportActionBar?.title = getString(R.string.app_exclusion_title)

        adapter = AppExclusionAdapter { app, excluded ->
            prefs.setExcluded(app.packageName, excluded)
            excludedPackages = prefs.getExcludedPackages()
            updateSummary()
        }

        binding.appList.layoutManager = LinearLayoutManager(this)
        binding.appList.adapter = adapter
        binding.appList.itemAnimator = null

        binding.searchInput.doAfterTextChanged { text ->
            filterApps(text?.toString().orEmpty())
        }

        binding.showSystemAppsSwitch.isChecked = includeSystemApps
        binding.showSystemAppsSwitch.setOnCheckedChangeListener { _, checked ->
            if (includeSystemApps != checked) {
                includeSystemApps = checked
                loadApps()
            }
        }

        binding.toolbar.setNavigationOnClickListener { finish() }

        loadApps()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putBoolean(KEY_INCLUDE_SYSTEM, includeSystemApps)
    }

    private fun loadApps() {
        binding.progressBar.visibility = View.VISIBLE
        binding.appList.visibility = View.GONE

        lifecycleScope.launch {
            val excluded = prefs.getExcludedPackages()
            allApps = withContext(Dispatchers.Default) {
                val loaded = InstalledAppsProvider.loadInstalledApps(
                    this@AppExclusionActivity,
                    includeSystemApps = includeSystemApps
                )
                mergeExcludedApps(loaded, excluded)
            }
            excludedPackages = excluded
            binding.progressBar.visibility = View.GONE
            binding.appList.visibility = View.VISIBLE
            filterApps(binding.searchInput.text?.toString().orEmpty())
            updateSummary()
        }
    }

    private fun filterApps(query: String) {
        val normalized = query.trim().lowercase()
        val filtered = if (normalized.isEmpty()) {
            allApps
        } else {
            allApps.filter {
                it.label.lowercase().contains(normalized) ||
                    it.packageName.lowercase().contains(normalized)
            }
        }
        adapter.submitList(filtered, excludedPackages)
        binding.emptyView.visibility = if (filtered.isEmpty()) View.VISIBLE else View.GONE
    }

    private fun updateSummary() {
        val count = excludedPackages.size
        binding.summaryText.text = resources.getQuantityString(
            R.plurals.app_exclusion_summary,
            count,
            count
        )
    }

    private fun mergeExcludedApps(loaded: List<AppInfo>, excluded: Set<String>): List<AppInfo> {
        if (excluded.isEmpty()) {
            return loaded
        }
        val known = loaded.map { it.packageName }.toMutableSet()
        val pm = packageManager
        val extras = excluded
            .filter { it !in known }
            .mapNotNull { packageName ->
                runCatching {
                    @Suppress("DEPRECATION")
                    val appInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                        pm.getApplicationInfo(
                            packageName,
                            PackageManager.ApplicationInfoFlags.of(0)
                        )
                    } else {
                        pm.getApplicationInfo(packageName, 0)
                    }
                    AppInfo(
                        packageName = appInfo.packageName,
                        label = appInfo.loadLabel(pm).toString().ifBlank { appInfo.packageName },
                        icon = runCatching { appInfo.loadIcon(pm) }
                            .getOrDefault(pm.defaultActivityIcon)
                    )
                }.getOrNull()
            }
        return (loaded + extras).sortedWith(compareBy({ it.label.lowercase() }, { it.packageName }))
    }

    companion object {
        private const val KEY_INCLUDE_SYSTEM = "include_system_apps"
    }
}
