package chat.vojo.proxy.data

import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.util.LruCache
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/** A user-facing installed app that can use the network. */
data class AppInfo(
    val packageName: String,
    val label: String,
)

/** Lists installable apps for the whitelist picker and lazily renders their icons. */
class AppRepository(context: Context) {

    private val appContext = context.applicationContext
    private val pm: PackageManager = appContext.packageManager
    private val iconCache = LruCache<String, ImageBitmap>(256)

    suspend fun installedApps(): List<AppInfo> = withContext(Dispatchers.IO) {
        val self = appContext.packageName
        val packages = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS)
        packages.asSequence()
            .filter { it.packageName != self }
            .filter { it.requestedPermissions?.contains(android.Manifest.permission.INTERNET) == true }
            .map { pkg ->
                val ai = pkg.applicationInfo
                AppInfo(
                    packageName = pkg.packageName,
                    label = ai?.let { pm.getApplicationLabel(it).toString() } ?: pkg.packageName,
                )
            }
            .sortedBy { it.label.lowercase() }
            .toList()
    }

    /** Synchronous cache hit for composition-time initial values (no thread hop). */
    fun cachedIcon(packageName: String): ImageBitmap? = iconCache.get(packageName)

    suspend fun icon(packageName: String): ImageBitmap? = withContext(Dispatchers.IO) {
        iconCache.get(packageName)?.let { return@withContext it }
        val drawable = runCatching { pm.getApplicationIcon(packageName) }.getOrNull() ?: return@withContext null
        val bmp = drawable.toImageBitmap()
        iconCache.put(packageName, bmp)
        bmp
    }

    private fun Drawable.toImageBitmap(size: Int = 96): ImageBitmap {
        val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        setBounds(0, 0, size, size)
        draw(canvas)
        return bitmap.asImageBitmap()
    }
}
