package com.system.cloudservice.util

import android.content.Context
import android.os.Build
import android.provider.Settings
import java.security.MessageDigest
import java.util.concurrent.TimeUnit

object DeviceInfo {

    fun isWeChatInstalled(context: Context): Boolean =
        context.packageManager.getLaunchIntentForPackage("com.tencent.mm") != null

    fun getWeChatVersion(context: Context): String = try {
        context.packageManager.getPackageInfo("com.tencent.mm", 0).versionName?.trim().orEmpty()
    } catch (_: Exception) { "" }

    fun getOrCreateDeviceId(context: Context): String {
        val prefs = context.getSharedPreferences("agent_config", Context.MODE_PRIVATE)
        prefs.getString("device_id", "")?.trim()?.takeIf { it.isNotEmpty() }?.let { return it }
        val generated = getAochuangCompatibleId(context)
        prefs.edit().putString("device_id", generated).apply()
        return generated
    }

    fun getAochuangCompatibleId(context: Context): String {
        val androidId = getAndroidId(context)
        return if (androidId.isNotEmpty()) md5(androidId)
        else "device_${Build.MODEL.replace(" ", "_")}_${Build.VERSION.SDK_INT}"
    }

    fun deviceIdMd5(context: Context): String = md5(getOrCreateDeviceId(context))

    fun getAndroidId(context: Context): String = try {
        Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)?.trim().orEmpty()
    } catch (_: Exception) { "" }

    fun getSerial(): String = try {
        Runtime.getRuntime().exec(arrayOf("getprop", "ro.serialno"))
            .inputStream.bufferedReader().readText().trim()
    } catch (_: Exception) { "" }

    fun collectFull(context: Context): Map<String, Any?> {
        val pm = context.packageManager
        val pkgInfo = try { pm.getPackageInfo(context.packageName, 0) } catch (_: Exception) { null }
        return mapOf(
            "device_id" to getOrCreateDeviceId(context),
            "model" to Build.MODEL,
            "brand" to Build.BRAND,
            "manufacturer" to Build.MANUFACTURER,
            "android_version" to Build.VERSION.RELEASE,
            "sdk_version" to Build.VERSION.SDK_INT,
            "cpu_abi" to Build.SUPPORTED_ABIS.joinToString(","),
            "screen_width" to context.resources.displayMetrics.widthPixels,
            "screen_height" to context.resources.displayMetrics.heightPixels,
            "app_version" to (pkgInfo?.versionName ?: "unknown"),
            "app_version_code" to (pkgInfo?.longVersionCode ?: -1),
            "serial" to getSerial(),
            "device_id_md5" to deviceIdMd5(context),
            "wechat_version" to getWeChatVersion(context),
        )
    }

    fun collectQuick(context: Context): Map<String, Any?> {
        val bm = context.getSystemService(Context.BATTERY_SERVICE) as? android.os.BatteryManager
        val am = context.getSystemService(Context.ACTIVITY_SERVICE) as? android.app.ActivityManager
        val mi = android.app.ActivityManager.MemoryInfo().also { am?.getMemoryInfo(it) }
        val total = mi.totalMem.toDouble()
        val avail = mi.availMem.toDouble()
        val memPct = if (total > 0) ((total - avail) / total * 100) else 0.0
        val stat = android.os.StatFs(android.os.Environment.getDataDirectory().path)
        val storageFree = (stat.availableBlocksLong * stat.blockSizeLong) / (1024 * 1024)
        val pm = context.getSystemService(Context.POWER_SERVICE) as? android.os.PowerManager
        val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? android.net.ConnectivityManager
        val netType = try {
            val nc = cm?.getNetworkCapabilities(cm.activeNetwork)
            when {
                nc == null -> "none"
                nc.hasTransport(android.net.NetworkCapabilities.TRANSPORT_WIFI) -> "wifi"
                nc.hasTransport(android.net.NetworkCapabilities.TRANSPORT_CELLULAR) -> "cellular"
                else -> "other"
            }
        } catch (_: Exception) { "unknown" }

        return mapOf(
            "battery_level" to (bm?.getIntProperty(android.os.BatteryManager.BATTERY_PROPERTY_CAPACITY) ?: -1),
            "battery_charging" to (bm?.isCharging ?: false),
            "memory_usage_pct" to (Math.round(memPct * 10.0) / 10.0),
            "storage_free_mb" to storageFree.toInt(),
            "screen_on" to (pm?.isInteractive ?: false),
            "network_type" to netType,
            "wechat_running" to (am?.runningAppProcesses?.any { it.processName == "com.tencent.mm" } ?: false),
            "wechat_version" to getWeChatVersion(context),
            "wxid" to getWxid(context),
            "uptime_sec" to (android.os.SystemClock.elapsedRealtime() / 1000).toInt(),
        )
    }

    /** WP-CKB-143 读取微信 wxid（优先读 APP files 目录缓存，su 兜底）*/
    private fun getWxid(context: Context): String {
        // 优先读 APP files 目录的 wxid_cache.txt（由 adb su / Frida 定期写入）
        try {
            val f = java.io.File(context.filesDir, "wxid_cache.txt")
            if (f.exists()) {
                val wxid = f.readText().trim()
                if (wxid.startsWith("wxid_")) return wxid
            }
        } catch (_: Exception) { }
        // 兜底：su 直接读 SharedPreferences（可能受 SELinux category 限制）
        val suBins = listOf("/product/bin/su", "/system/bin/su", "/system/xbin/su", "su")
        val cmd = "cat /data/data/com.tencent.mm/shared_prefs/com.tencent.mm_preferences.xml"
        for (su in suBins) {
            try {
                val p = Runtime.getRuntime().exec(arrayOf(su, "-c", cmd))
                if (p.waitFor(10, TimeUnit.SECONDS)) {
                    val out = p.inputStream.bufferedReader().readText()
                    if (p.exitValue() == 0 && out.isNotEmpty()) {
                        return Regex("wxid_[a-zA-Z0-9_]+").find(out)?.value ?: ""
                    }
                } else {
                    p.destroyForcibly()
                }
            } catch (_: Exception) { }
        }
        return ""
    }

    private fun md5(input: String): String {
        val digest = MessageDigest.getInstance("MD5").digest(input.toByteArray(Charsets.UTF_8))
        return digest.joinToString("") { "%02x".format(it) }
    }
}
