package com.dphms.netguard

import java.io.BufferedReader
import java.io.InputStreamReader

/**
 * Runs inside the Shizuku server process with ADB/shell privileges.
 * Runtime.getRuntime().exec() here has the same permissions as adb shell.
 */
class NetGuardServiceImpl : INetGuardService.Stub() {

    private data class ShellResult(val exitCode: Int, val stdout: String, val stderr: String)

    private fun runCommand(command: String): ShellResult {
        return try {
            val process = Runtime.getRuntime().exec(arrayOf("sh", "-c", command))
            val stdout = process.inputStream.bufferedReader().use { it.readText() }
            val stderr = process.errorStream.bufferedReader().use { it.readText() }
            val exitCode = process.waitFor()
            ShellResult(exitCode, stdout, stderr)
        } catch (e: Exception) {
            ShellResult(-1, "", e.message ?: "Execution error")
        }
    }

    override fun executeCommand(command: String?): String {
        if (command.isNullOrBlank()) return "ERROR: Empty command"
        val result = runCommand(command)
        return if (result.stdout.isNotBlank()) result.stdout else result.stderr
    }

    override fun listThirdPartyPackages(): Array<String> {
        val result = runCommand("pm list packages -3")
        return result.stdout.lines()
            .map { it.trim().removePrefix("package:") }
            .filter { it.isNotBlank() }
            .toTypedArray()
    }

    override fun listAllPackages(): Array<String> {
        val result = runCommand("pm list packages")
        return result.stdout.lines()
            .map { it.trim().removePrefix("package:") }
            .filter { it.isNotBlank() }
            .toTypedArray()
    }

    override fun getPackagePermissions(packageName: String?): Array<String> {
        if (packageName.isNullOrBlank()) return emptyArray()
        val result = runCommand("dumpsys package $packageName")
        val permissions = mutableSetOf<String>()
        val regex = Regex("android\\.permission\\.[A-Z0-9_]+")
        regex.findAll(result.stdout).forEach { permissions.add(it.value) }
        return permissions.toTypedArray()
    }

    override fun getPackageInfo(packageName: String?): String {
        if (packageName.isNullOrBlank()) return "Invalid package"
        val result = runCommand("dumpsys package $packageName")
        return if (result.stdout.isNotBlank()) result.stdout else result.stderr
    }

    override fun getInstallSource(packageName: String?): String {
        if (packageName.isNullOrBlank()) return "Invalid package"
        val result = runCommand("cmd package install-source $packageName 2>/dev/null || pm path $packageName")
        return result.stdout.trim()
    }

    // Known malware/adware package families
    private val malwareFamilies = setOf(
        "com.android.systemservice", "com.android.service", "com.system.service",
        "com.google.update", "com.android.securityupdate", "com.systemupdate",
        "com.android.systemui.update", "com.security.service", "com.phone.service",
        "com.android.telephony.service", "com.system.security",
        "com.mobi.tools", "com.apktool", "com.drozer",
        "com.metasploit", "com.payload", "com.shell.inject",
        "com.android.hidden", "com.spy", "com.tracker", "com.monitor",
        "com.keylogger", "com.spyware", "com.malware"
    )

    // Dangerous permissions
    private val dangerousPerms = setOf(
        "android.permission.SEND_SMS", "android.permission.RECEIVE_SMS",
        "android.permission.READ_SMS", "android.permission.RECEIVE_MMS",
        "android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS",
        "android.permission.READ_CALL_LOG", "android.permission.WRITE_CALL_LOG",
        "android.permission.PROCESS_OUTGOING_CALLS", "android.permission.CALL_PHONE",
        "android.permission.RECORD_AUDIO", "android.permission.CAMERA",
        "android.permission.REQUEST_INSTALL_PACKAGES",
        "android.permission.BIND_DEVICE_ADMIN",
        "android.permission.BIND_ACCESSIBILITY_SERVICE",
        "android.permission.SYSTEM_ALERT_WINDOW",
        "android.permission.READ_EXTERNAL_STORAGE",
        "android.permission.WRITE_EXTERNAL_STORAGE",
        "android.permission.READ_PHONE_STATE",
        "android.permission.ACCESS_FINE_LOCATION",
        "android.permission.ACCESS_COARSE_LOCATION"
    )

    // Spyware permission combos
    private val spywareCombos = listOf(
        setOf("RECORD_AUDIO", "READ_SMS"),
        setOf("RECORD_AUDIO", "ACCESS_FINE_LOCATION"),
        setOf("READ_SMS", "SEND_SMS", "READ_CONTACTS"),
        setOf("READ_CONTACTS", "SEND_SMS"),
        setOf("BIND_ACCESSIBILITY_SERVICE", "REQUEST_INSTALL_PACKAGES"),
        setOf("BIND_DEVICE_ADMIN", "SYSTEM_ALERT_WINDOW"),
        setOf("CAMERA", "RECORD_AUDIO", "READ_SMS"),
        setOf("READ_SMS", "ACCESS_FINE_LOCATION"),
        setOf("PROCESS_OUTGOING_CALLS", "RECORD_AUDIO"),
        setOf("READ_CONTACTS", "READ_CALL_LOG", "SEND_SMS")
    )

    private fun classifyApp(pkg: String, perms: Set<String>): String? {
        val isMalware = malwareFamilies.any { pkg.contains(it) || it.contains(pkg) }

        val permNames = perms.map { it.replace("android.permission.", "") }.toSet()
        var spywareRisk = false
        for (combo in spywareCombos) {
            if (permNames.containsAll(combo)) { spywareRisk = true; break }
        }

        val hasOverlay = perms.contains("android.permission.SYSTEM_ALERT_WINDOW")
        val hasAccessibility = perms.contains("android.permission.BIND_ACCESSIBILITY_SERVICE")
        val hasInstall = perms.contains("android.permission.REQUEST_INSTALL_PACKAGES")
        val overlayAbuse = hasOverlay && (hasAccessibility || hasInstall)

        val dangerous = perms.filter { it in dangerousPerms }

        val severity = when {
            isMalware -> "CRITICAL"
            spywareRisk -> "HIGH"
            overlayAbuse -> "HIGH"
            dangerous.size >= 5 -> "MEDIUM"
            dangerous.isNotEmpty() -> "LOW"
            else -> null
        }

        return severity?.let { sev ->
            val detail = when {
                isMalware -> "Matches known malware family"
                spywareRisk -> "Spyware permission combo detected"
                overlayAbuse -> "Overlay + install/accessibility abuse"
                dangerous.size >= 5 -> "Multiple dangerous permissions (${dangerous.size})"
                else -> "Has flagged permission: ${dangerous.first()}"
            }
            val permList = dangerous.joinToString(",") { it.replace("android.permission.", "") }
            "$pkg|$sev|$detail|$permList"
        }
    }

    override fun scanAllApps(): Array<String> {
        val packages = listThirdPartyPackages()
        val results = mutableListOf<String>()
        for (pkg in packages) {
            val perms = getPackagePermissions(pkg).toSet()
            classifyApp(pkg, perms)?.let { results.add(it) }
        }
        return results.toTypedArray()
    }

    override fun scanDangerousPermissions(): Array<String> {
        val packages = listThirdPartyPackages()
        val results = mutableListOf<String>()
        for (pkg in packages) {
            val perms = getPackagePermissions(pkg).toSet()
            val dangerous = perms.filter { it in dangerousPerms }
            if (dangerous.isNotEmpty()) {
                val severity = if (dangerous.size >= 5) "MEDIUM" else "LOW"
                val permList = dangerous.joinToString(",") { it.replace("android.permission.", "") }
                results.add("$pkg|$severity|${dangerous.size} dangerous permission(s)|$permList")
            }
        }
        return results.toTypedArray()
    }

    override fun scanOverlayAbuse(): Array<String> {
        val packages = listThirdPartyPackages()
        val results = mutableListOf<String>()
        for (pkg in packages) {
            val perms = getPackagePermissions(pkg).toSet()
            val hasOverlay = perms.contains("android.permission.SYSTEM_ALERT_WINDOW")
            val hasAccessibility = perms.contains("android.permission.BIND_ACCESSIBILITY_SERVICE")
            val hasInstall = perms.contains("android.permission.REQUEST_INSTALL_PACKAGES")
            val hasDeviceAdmin = perms.contains("android.permission.BIND_DEVICE_ADMIN")

            if (hasOverlay || hasAccessibility || hasInstall || hasDeviceAdmin) {
                val flags = mutableListOf<String>()
                if (hasOverlay) flags.add("OVERLAY")
                if (hasAccessibility) flags.add("ACCESSIBILITY")
                if (hasInstall) flags.add("INSTALL_PACKAGES")
                if (hasDeviceAdmin) flags.add("DEVICE_ADMIN")
                val severity = if (flags.size >= 2) "HIGH" else "MEDIUM"
                results.add("$pkg|$severity|${flags.joinToString(" + ")}|")
            }
        }
        return results.toTypedArray()
    }

    override fun scanUnknownSources(): Array<String> {
        val packages = listThirdPartyPackages()
        val results = mutableListOf<String>()
        for (pkg in packages) {
            val installer = getInstallSource(pkg)
            val isUnknown = installer.contains("UNKNOWN") || installer.contains("null") || installer.isBlank()
            val isPlayStore = installer.contains("com.android.vending") || installer.contains("com.google.android")
            if (isUnknown && !isPlayStore) {
                results.add("$pkg|MEDIUM|Installed from unknown source (sideloaded)|")
            }
        }
        return results.toTypedArray()
    }
}
