package eu.darken.sdmse.common.permissions

import android.app.AppOpsManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import eu.darken.sdmse.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.sdmse.common.debug.logging.Logging.Priority.WARN
import eu.darken.sdmse.common.debug.logging.log
import eu.darken.sdmse.common.debug.logging.logTag
import eu.darken.sdmse.common.device.DeviceDetective
import eu.darken.sdmse.common.device.RomType


@Suppress("ClassName")
sealed class Permission(
    val permissionId: String
) {
    open fun isGranted(context: Context): Boolean {
        return ContextCompat.checkSelfPermission(context, permissionId) == PackageManager.PERMISSION_GRANTED
    }

    object POST_NOTIFICATIONS
        : Permission("android.permission.POST_NOTIFICATIONS"), RuntimePermission

    @RequiresApi(Build.VERSION_CODES.R)
    object MANAGE_EXTERNAL_STORAGE
        : Permission("android.permission.MANAGE_EXTERNAL_STORAGE"), Specialpermission {
        override fun isGranted(context: Context): Boolean {
            return Environment.isExternalStorageManager()
        }

        override fun createIntent(context: Context, deviceDetective: DeviceDetective): Intent = Intent().apply {
            action = Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
            data = Uri.fromParts("package", context.packageName, null)
        }

        override fun createIntentFallback(context: Context): Intent = Intent().apply {
            action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
        }
    }

    object WRITE_EXTERNAL_STORAGE
        : Permission("android.permission.WRITE_EXTERNAL_STORAGE"), RuntimePermission

    object READ_EXTERNAL_STORAGE
        : Permission("android.permission.READ_EXTERNAL_STORAGE"), RuntimePermission

    object PACKAGE_USAGE_STATS
        : Permission("android.permission.PACKAGE_USAGE_STATS"), Specialpermission {
        private val TAG = logTag("Permission", "UsageStats")


        @Suppress("DEPRECATION")
        override fun isGranted(context: Context): Boolean {
            val applicationInfo = context.packageManager.getApplicationInfo(context.packageName, 0)
            val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
            val mode = appOpsManager.checkOpNoThrow(
                AppOpsManager.OPSTR_GET_USAGE_STATS,
                applicationInfo.uid,
                applicationInfo.packageName
            )
            log(TAG, VERBOSE) { "checkOpNoThrow(OPSTR_GET_USAGE_STATS)=$mode" }

            return when (mode) {
                AppOpsManager.MODE_ALLOWED -> {
                    log(TAG, VERBOSE) { "MODE_ALLOWED: Permission explicitly allowed via AppOps" }
                    true
                }

                AppOpsManager.MODE_IGNORED, AppOpsManager.MODE_ERRORED -> {
                    log(TAG, VERBOSE) { "MODE_IGNORED|MODE_ERRORED: Permission explicitly denied via AppOps" }
                    false
                }

                AppOpsManager.MODE_DEFAULT -> {
                    log(TAG, VERBOSE) { "MODE_DEFAULT: Has not been changed or errorneous report." }
                    val result = ContextCompat.checkSelfPermission(context, permissionId)
                    log(TAG, VERBOSE) { "checkSelfPermission(PACKAGE_USAGE_STATS)=$result" }
                    result == PackageManager.PERMISSION_GRANTED
                }

                else -> {
                    log(TAG, WARN) { "Unknown mode $mode, assuming permission denied" }
                    false
                }
            }
        }

        override fun createIntent(context: Context, deviceDetective: DeviceDetective): Intent {
            val defaultIntent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
            return when {
                defaultIntent.resolveActivities(context).isNotEmpty() -> return defaultIntent
                deviceDetective.getROMType() == RomType.ANDROID_TV -> Intent(Settings.ACTION_APPLICATION_SETTINGS)
                else -> Intent(Settings.ACTION_SETTINGS)
            }
        }
    }

    data object WRITE_SECURE_SETTINGS
        : Permission("android.permission.WRITE_SECURE_SETTINGS")

    data object QUERY_ALL_PACKAGES
        : Permission("android.permission.QUERY_ALL_PACKAGES")

    // Non-AOSP permission from Chinese TAF standard (TTAF 108-2022).
    // Required by Chinese ROMs (HyperOS, ColorOS, OriginOS, HarmonyOS) to access the full app list.
    // Does not exist on AOSP/Pixel/Samsung — isGranted() returns true when absent.
    data object GET_INSTALLED_APPS
        : Permission("com.android.permission.GET_INSTALLED_APPS"), RuntimePermission {
        override fun isGranted(context: Context): Boolean {
            val exists = try {
                context.packageManager.getPermissionInfo(permissionId, 0)
                true
            } catch (_: Exception) {
                false
            }
            if (!exists) return true
            return super.isGranted(context)
        }
    }

    fun Intent.resolveActivities(context: Context): Collection<ResolveInfo> =
        context.packageManager.queryIntentActivities(
            this,
            PackageManager.MATCH_DEFAULT_ONLY
        )

    companion object {
        // Without lazy there is an NPE: https://youtrack.jetbrains.com/issue/KT-25957
        // MANAGE_EXTERNAL_STORAGE is @RequiresApi(R); referencing it in this version-agnostic
        // registry is safe (the object is only constructed, its API-30 methods are guarded at use).
        @Suppress("NewApi")
        val values: List<Permission> by lazy {
            listOf(
                POST_NOTIFICATIONS,
                MANAGE_EXTERNAL_STORAGE,
                WRITE_EXTERNAL_STORAGE,
                READ_EXTERNAL_STORAGE,
                PACKAGE_USAGE_STATS,
                WRITE_SECURE_SETTINGS,
                QUERY_ALL_PACKAGES,
                GET_INSTALLED_APPS,
            )
        }

        fun fromId(rawId: String) = values.singleOrNull { it.permissionId == rawId }
    }
}

interface RuntimePermission

interface Specialpermission {
    fun createIntent(context: Context, deviceDetective: DeviceDetective): Intent
    fun createIntentFallback(context: Context): Intent? = null
}