package com.adealink.weparty.permission

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Build.VERSION
import android.provider.Settings
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.adealink.frame.base.PermissionNoGrantError
import com.adealink.frame.base.Rlt
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.log.Log
import com.adealink.frame.util.AppUtil
import com.adealink.weparty.commonui.widget.CommonDialog
import com.adealink.weparty.permission.constant.TAG_PERMISSION
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import kotlin.coroutines.resume

@SuppressLint("CheckResult")
object PermissionUtils {

    const val PERMISSION_TIP_MAX_COUNT = 3

    suspend fun getPermissions(activity: FragmentActivity, vararg permissions: String): Rlt<Any> {
        return withContext(Dispatcher.UI) {
            suspendCancellableCoroutine { continuation ->
                getRxPermissions(activity)
                    .request(*permissions).subscribe { granted ->
                        if (continuation.isActive) {
                            if (granted) {
                                continuation.resume(Rlt.Success(Any()))
                            } else {
                                continuation.resume(Rlt.Failed(PermissionNoGrantError()))
                            }
                        }
                    }
            }
        }
    }

    fun requestPermissionWithRetry(
        activity: FragmentActivity,
        permission: String,
        tip: String,
        tipCount: Int,
        callback: (granted: Boolean, tipLimit: Boolean) -> Unit
    ) {
        getRxPermissions(activity).requestEach(permission).subscribe {
            val permissionName = it.name
            when {
                it.granted -> {
                    Log.d(TAG_PERMISSION, "$permissionName is granted")
                    callback(true, false)
                }

                it.shouldShowRequestPermissionRationale -> {
                    Log.e(
                        TAG_PERMISSION,
                        "$permissionName is denied without ask never again"
                    )
                    if (tipCount >= PERMISSION_TIP_MAX_COUNT) {
                        callback(false, true)
                        return@subscribe
                    }

                    CommonDialog.Builder()
                        .message(tip)
                        .onPositive {
                            getRxPermissions(activity).request(permissionName)
                                .subscribe { granted ->
                                    if (granted) {
                                        Log.d(
                                            TAG_PERMISSION,
                                            "retry $permissionName is granted"
                                        )
                                        callback(true, false)
                                    } else {
                                        Log.e(
                                            TAG_PERMISSION,
                                            "retry $permissionName is denied"
                                        )
                                        callback(false, false)
                                    }
                                }
                        }
                        .onNegative { callback(false, false) }
                        .setShowDefaultCancel(true)
                        .build()
                        .show(activity.supportFragmentManager)
                }

                else -> {
                    if (tipCount >= PERMISSION_TIP_MAX_COUNT) {
                        callback(false, true)
                        return@subscribe
                    }

                    Log.e(TAG_PERMISSION, "$permissionName is denied with ask never again")
                    CommonDialog.Builder()
                        .message(tip)
                        .onPositive {
                            startPermissionSettingActivity(activity)
                            callback(false, false)
                        }
                        .onNegative { callback(false, false) }
                        .setShowDefaultCancel(true)
                        .build()
                        .show(activity.supportFragmentManager)
                }
            }
        }
    }

    fun requestPermissions(
        activity: FragmentActivity,
        permissions: List<String>,
        tip: String,
        onGranted: () -> Unit,
        onDenied: () -> Unit
    ) {
        if (hasPermissions(activity, *permissions.toTypedArray())) {
            onGranted.invoke()
            return
        }
        showRequestPermissionDialog(
            activity,
            tip,
            onConfirm = {
                getRxPermissions(activity).request(*permissions.toTypedArray()).subscribe {
                    if (it) {
                        onGranted.invoke()
                    } else {
                        onDenied.invoke()
                    }
                }
            },
            onCancel = {
                onDenied.invoke()
            }
        )
    }

    fun showRequestPermissionDialog(
        activity: FragmentActivity,
        tip: String,
        onConfirm: () -> Unit,
        onCancel: () -> Unit
    ) {
        var hasClick = false
        CommonDialog.Builder()
            .message(tip)
            .onPositive {
                hasClick = true
                onConfirm.invoke()
            }
            .onNegative {
                hasClick = true
                onCancel.invoke()
            }
            .onDismiss {
                if (!hasClick) {
                    onCancel.invoke()
                }
            }
            .dismissAfterClick(true)
            .canceledOnTouchOutside(false)
            .setShowDefaultCancel(true)
            .build()
            .show(activity.supportFragmentManager)
    }

    fun getRxPermissions(activity: FragmentActivity): RxPermissions {
        return RxPermissions(activity)
    }

    private val isOverMarshmallow: Boolean
        get() = VERSION.SDK_INT >= 23

    fun hasPermissions(context: Context, vararg permissions: String): Boolean {
        return if (isOverMarshmallow && permissions.isNotEmpty()) {
            val permissionArray: Array<String>? = permissions as? Array<String>
            for (index in permissions.indices) {
                val p = permissionArray?.get(index)
                if (!p.isNullOrEmpty()) {
                    val result = ActivityCompat.checkSelfPermission(context, p)
                    if (result != 0) {
                        return false
                    }
                }
            }
            true
        } else {
            true
        }
    }

    fun findDeniedPermissions(context: Context, vararg permissions: String): List<String?> {
        val denyList = mutableListOf<String>()
        return if (isOverMarshmallow && permissions.isNotEmpty()) {
            val permissionArray: Array<String>? = permissions as? Array<String>
            for (index in permissions.indices) {
                val p = permissionArray?.get(index)
                if (!p.isNullOrEmpty()) {
                    val result = ActivityCompat.checkSelfPermission(context, p)
                    if (result != 0) {
                        denyList.add(p)
                    }
                }
            }
            denyList
        } else {
            denyList
        }
    }

    private val permissionSettingIntent: Intent
        get() {
            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
            intent.data = Uri.parse("package:${AppUtil.appContext.packageName}")
            return intent
        }

    fun startPermissionSettingActivity(fragment: Fragment?) {
        if (fragment != null) {
            val intent = permissionSettingIntent
            fragment.startActivity(intent)
        }
    }

    fun startPermissionSettingActivity(activity: Activity?) {
        if (activity != null) {
            val intent = permissionSettingIntent
            try {
                activity.startActivity(intent)
            } catch (e: Exception) {

            }
        }
    }

    fun goNotificationSettingActivity(activity: Activity?) {
        val intent = Intent()
        try {
            if (VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //8.0及以后版本
                intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
                intent.putExtra(Settings.EXTRA_APP_PACKAGE, AppUtil.appContext.packageName)
                intent.putExtra(Settings.EXTRA_CHANNEL_ID, AppUtil.appContext.applicationInfo.uid)
            } else {
                //5.0-7.1
                intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
                intent.putExtra("app_package", AppUtil.appContext.packageName)
                intent.putExtra("app_uid", AppUtil.appContext.applicationInfo.uid)
            }
            activity?.startActivity(intent)
        } catch (e: Exception) {
            startPermissionSettingActivity(activity)
        }
    }
}