package com.gh.gamecenter.common.utils

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.PermissionInfo
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.view.Gravity
import android.view.LayoutInflater
import android.view.Window
import android.view.WindowManager
import android.widget.FrameLayout
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.therouter.TheRouter
import com.gh.gamecenter.common.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.databinding.DialogCalendarPermissionBinding
import com.gh.gamecenter.common.databinding.DialogExternalStoragePermissionIntroBinding
import com.gh.gamecenter.common.dialog.ManageExternalStoragePermissionDialogFragment
import com.gh.gamecenter.common.view.ImprovedBulletSpan
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IAppProvider
import com.gh.gamecenter.core.provider.IDirectProvider
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.core.utils.SPUtils
import com.lightgame.utils.AppManager
import com.tbruyelle.rxpermissions2.RxPermissions

object PermissionHelper {

    const val INSTALL_PERMISSION_CODE = 100
    const val MANAGE_EXTERNAL_STORAGE_PERMISSION_CODE = 1000

    private const val PERMISSION_GET_INSTALLED_LIST = "com.android.permission.GET_INSTALLED_APPS"

    private const val HINT_CHECK_USAGE = "查看权限应用场景 "

    /**
     * 请求获取已安装列表权限
     */
    @SuppressLint("CheckResult")
    fun requestGetInstalledAppsListPermission(
        activity: FragmentActivity,
        ignorePermanentlyDenied: Boolean = false,
        resultCallback: (Boolean) -> Unit
    ) {
        try {
            val rxPermission = RxPermissions(activity)
            rxPermission
                .requestEachCombined(PERMISSION_GET_INSTALLED_LIST)
                .subscribe { permission ->
                    when {
                        permission.granted -> {
                            resultCallback.invoke(true)
                        }

                        permission.shouldShowRequestPermissionRationale -> {
                            resultCallback.invoke(false)
                        }

                        else -> {
                            // 忽略永久拒绝的提示跳转响应
                            if (ignorePermanentlyDenied) {
                                resultCallback.invoke(false)
                                return@subscribe
                            }

                            if (SPUtils.getBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_GET_INSTALL_LIST_PERMISSION)) {
                                showPermissionPermanentlyDeniedDialog(
                                    activity = activity,
                                    permissionName = "获取已安装应用列表权限"
                                ) {
                                    resultCallback.invoke(false)
                                }
                            } else {
                                SPUtils.setBoolean(
                                    Constants.SP_USER_HAS_PERMANENTLY_DENIED_GET_INSTALL_LIST_PERMISSION,
                                    true
                                )
                                resultCallback.invoke(false)
                            }
                        }
                    }
                }
        } catch (e: Exception) {
            resultCallback.invoke(false)
        }
    }

    @SuppressLint("CheckResult")
    @JvmStatic
    fun checkStoragePermissionBeforeAction(
        context: Context,
        gameId: String = "",
        gameName: String = "",
        gameType: String = "",
        gameFormat: String? = "",
        emptyCallback: EmptyCallback
    ) {

        // 无需申请存储权限的场景 (gameFormat 等于 APK/XAPK/APKS)
        val ignoreStoragePermission =
            gameFormat == Constants.APK_FORMAT || gameFormat == Constants.XAPK_FORMAT || gameFormat == Constants.XAPK_APKS_FORMAT

        if (ignoreStoragePermission) {
            emptyCallback.onCallback()
            return
        }

        if (context is FragmentActivity) {
            if (context.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
                && context.checkCallingOrSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
            ) {
                emptyCallback.onCallback()
                SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, false)
            } else {
                showStoragePermissionDialogAndRequestPermission(context, emptyCallback)
            }
        }
    }

    /**
     * 请求存储权限如果需要的话
     * @param activity FragmentActivity 上下文
     * @param resultCallback 权限是否已经拥有的结果回调
     */
    @SuppressLint("CheckResult")
    private fun requestStoragePermissionIfNeeded(activity: FragmentActivity, resultCallback: (Boolean) -> Unit) {
        tryWithDefaultCatch {
            val rxPermission = RxPermissions(activity)
            rxPermission
                .requestEachCombined(
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE
                )
                .subscribe { permission ->
                    when {
                        permission.granted -> {
                            // 获得存储权限后刷新 gid 避免下载仍需实名
                            TheRouter.get(IAppProvider::class.java)?.refreshGid()

                            // 延迟 100ms 确保能够正常获取到 gid
                            AppExecutor.uiExecutor.executeWithDelay({
                                resultCallback.invoke(true)
                            }, 100)
                            SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, false)
                        }

                        permission.shouldShowRequestPermissionRationale -> {
                            // do nothing
                            resultCallback.invoke(false)
                        }

                        else -> {
                            if (SPUtils.getBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION)) {
                                showPermissionPermanentlyDeniedDialog(
                                    activity = activity,
                                    permissionName = "存储权限"
                                ) {
                                    resultCallback.invoke(false)
                                }
                            } else {
                                SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, true)
                                resultCallback.invoke(false)
                            }
                        }
                    }
                }
        }
    }

    private fun showPermissionPermanentlyDeniedDialog(
        activity: Activity,
        permissionName: String,
        dimAmount: Float = 0.2F,
        callback: () -> Unit,
    ) {
        DialogHelper.showDialog(
            context = activity,
            title = "权限申请",
            content = "在设置-应用-光环助手-权限中开启${permissionName}，以保证能正常使用相关功能",
            confirmText = "去设置",
            cancelText = "放弃",
            confirmClickCallback = {
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                intent.data = Uri.parse("package:" + activity.packageName)
                activity.startActivity(intent)
            },
            uiModificationCallback = { wrapper ->
                wrapper.dialog.window?.setGravity(Gravity.BOTTOM)
                wrapper.dialog.window?.setDimAmount(dimAmount)
                val wmlp = wrapper.dialog.window?.attributes
                wmlp?.y = 30F.dip2px()
                wrapper.dialog.setOnDismissListener {
                    callback.invoke()
                }
            })
    }

    /**
     * 跳转到权限设置
     *
     * @param activity
     */
    @JvmStatic
    fun toPermissionSetting(activity: Activity) {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
            toSystemConfig(activity)
        } else {
            try {
                toApplicationInfo(activity)
            } catch (e: Exception) {
                e.printStackTrace()
                toSystemConfig(activity)
            }

        }
    }

    /**
     * 应用信息界面
     *
     * @param activity
     */
    private fun toApplicationInfo(activity: Activity) {
        val localIntent = Intent()
        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        localIntent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
        localIntent.data = Uri.fromParts("package", activity.packageName, null)
        activity.startActivity(localIntent)
    }

    /**
     * 系统设置界面
     *
     * @param activity
     */
    private fun toSystemConfig(activity: Activity) {
        try {
            val intent = Intent(Settings.ACTION_SETTINGS)
            activity.startActivity(intent)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 展示获取已安装列表权限提示弹窗并请求权限
     */
    fun showGetInstalledAppsListPermissionDialog(
        activity: FragmentActivity,
        requestPermission: Boolean,
        ignorePermanentlyDenied: Boolean = false,
        resultCallback: (Boolean) -> Unit
    ): Dialog? {
        val solidContext = activity as? Activity ?: AppManager.getInstance().currentActivity() ?: return null
        val dialog = Dialog(solidContext, R.style.GhAlertDialog)

        val binding = DialogExternalStoragePermissionIntroBinding.inflate(LayoutInflater.from(solidContext))

        binding.container.updateLayoutParams<FrameLayout.LayoutParams> {
            height = 100F.dip2px()
        }

        val spannableBuilder = SpannableStringBuilder("当您使用APP时，以下场景向您申请已安装列表权限：\n")

        val liStringList = arrayListOf("游戏更新提醒")

        for (li in liStringList) {
            val liSpanned = SpannableStringBuilder(li).apply {
                setSpan(
                    ImprovedBulletSpan(bulletRadius = 1.5F.dip2px(), gapWidth = 14F.dip2px()),
                    0,
                    li.length,
                    Spanned.SPAN_INCLUSIVE_EXCLUSIVE
                )
            }
            spannableBuilder.append(liSpanned)
        }

        binding.contentTv.text = spannableBuilder
        binding.titleTv.text = "权限使用说明"

        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setContentView(binding.root)
        dialog.window?.setDimAmount(0F)
        dialog.window?.setGravity(Gravity.TOP)
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

        dialog.show()

        if (requestPermission) {
            requestGetInstalledAppsListPermission(activity, ignorePermanentlyDenied) { isGranted ->
                resultCallback.invoke(isGranted)
                dialog.dismiss()
            }
        }

        return dialog
    }

    /**
     * 展示获取提示弹窗并请求存储权限
     */
    private fun showStoragePermissionDialogAndRequestPermission(
        activity: FragmentActivity,
        emptyCallback: EmptyCallback
    ) {
        val solidContext = activity as? Activity ?: AppManager.getInstance().currentActivity() ?: return
        val dialog = Dialog(solidContext, R.style.GhAlertDialog)

        val binding = DialogExternalStoragePermissionIntroBinding.inflate(LayoutInflater.from(solidContext))

        val spannableBuilder = SpannableStringBuilder("当您使用APP时，在以下的场景向您请求授权存储权限:\n")

        val liStringList = arrayListOf(
            "游戏上传及导入\n",
            "使用安装包清理功能\n",
            "图片保存（游戏详情、游戏单、资讯论坛、个人主页、信息中心、设置微信提醒）\n",
            "图片/视频上传（个人主页信息修改、内容发布/编辑、游戏投稿、意见反馈、实名认证人工审核）"
        )
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
            liStringList.add(0, "下载/安装xapk/apks游戏\n")
        }

        for (li in liStringList) {
            val liSpanned = SpannableStringBuilder(li).apply {
                setSpan(
                    ImprovedBulletSpan(bulletRadius = 1.5F.dip2px(), gapWidth = 14F.dip2px()),
                    0,
                    li.length,
                    Spanned.SPAN_INCLUSIVE_EXCLUSIVE
                )
            }
            spannableBuilder.append(liSpanned)
        }

        binding.contentTv.text = spannableBuilder
        binding.titleTv.text = "权限使用说明"

        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setContentView(binding.root)
        dialog.window?.setDimAmount(0F)
        dialog.window?.setGravity(Gravity.TOP)
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

        requestStoragePermissionIfNeeded(activity) { granted ->
            if (granted) {
                emptyCallback.onCallback()
            }
            dialog.dismiss()
        }

        dialog.show()
    }

    fun checkManageAllFilesOrStoragePermissionBeforeAction(context: Context, emptyCallback: EmptyCallback) {
        val activity =
            context as? FragmentActivity ?: AppManager.getInstance().currentActivity() as? FragmentActivity ?: return
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (Environment.isExternalStorageManager()) {
                emptyCallback.onCallback()
            } else {
                showManageExternalStoragePermissionDialogAndRequestPermission(activity, emptyCallback)
            }
        } else {
            checkStoragePermissionBeforeAction(activity, emptyCallback = emptyCallback)
        }
    }

    /**
     * 展示获取提示弹窗并请求所有文件访问权限(MANAGE_EXTERNAL_STORAGE)
     */
    @RequiresApi(Build.VERSION_CODES.R)
    private fun showManageExternalStoragePermissionDialogAndRequestPermission(
        activity: FragmentActivity,
        emptyCallback: EmptyCallback
    ) {
        val dialog = Dialog(activity, R.style.GhAlertDialog)

        val binding = DialogExternalStoragePermissionIntroBinding.inflate(LayoutInflater.from(activity))

        val spannableBuilder = SpannableStringBuilder("当您使用APP时，在以下的场景向您申请所有文件访问权限:\n")

        val liStringList = arrayListOf(
            "安装包清理功能\n",
            "下载/安装xapk/apks游戏"
        )

        for (li in liStringList) {
            val liSpanned = SpannableStringBuilder(li).apply {
                setSpan(
                    ImprovedBulletSpan(bulletRadius = 1.5F.dip2px(), gapWidth = 14F.dip2px()),
                    0,
                    li.length,
                    Spanned.SPAN_INCLUSIVE_EXCLUSIVE
                )
            }
            spannableBuilder.append(liSpanned)
        }

        binding.contentTv.text = spannableBuilder
        binding.titleTv.text = "权限使用说明"

        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setContentView(binding.root)
        dialog.window?.setDimAmount(0F)
        dialog.window?.setGravity(Gravity.TOP)
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        dialog.show()

        ManageExternalStoragePermissionDialogFragment.show(activity) { grant ->
            if (grant) {
                emptyCallback.onCallback()
            }
            dialog.dismiss()
        }
    }

    @JvmStatic
    fun isGetInstalledListPermissionDisabled(context: Context): Boolean {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false

        val permissionInfo: PermissionInfo?
        return try {
            permissionInfo = context.packageManager.getPermissionInfo(PERMISSION_GET_INSTALLED_LIST, 0)
            (permissionInfo != null
                    && permissionInfo.protectionLevel and PermissionInfo.PROTECTION_MASK_BASE == PermissionInfo.PROTECTION_DANGEROUS
                    && PackageManager.PERMISSION_GRANTED != context.checkSelfPermission(PERMISSION_GET_INSTALLED_LIST))
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    /**
     * 开启安装未知来源权限
     */
    fun toInstallPermissionSetting(activity: Activity) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            toSystemConfig(activity)
        } else {
            val packageURI = Uri.fromParts("package", activity.packageName, null)
            val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI)
            activity.startActivityForResult(intent, INSTALL_PERMISSION_CODE)
        }
    }

    /**
     * 获取开启安装位置来源权限 Intent
     */
    fun getToInstallPermissionSettingIntent(context: Context): Intent {
        return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            Intent(Settings.ACTION_SETTINGS)
        } else {
            val packageURI = Uri.fromParts("package", context.packageName, null)
            Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI)
        }
    }

    /**
     * 在执行 emptyCallback 的 action 前先判断是否有获取已安装列表的权限
     */
    @SuppressLint("CheckResult")
    @JvmStatic
    fun checkGetInstalledAppsListBeforeAction(
        context: Context,
        resultCallback: (Boolean) -> Unit
    ) {
        if (context is AppCompatActivity && isGetInstalledListPermissionDisabled(context)) {
            showDialogBeforeRequestingGetInstalledListDialog(context, resultCallback)
        } else {
            resultCallback.invoke(true)
        }
    }

    private fun showDialogBeforeRequestingGetInstalledListDialog(
        context: FragmentActivity,
        resultCallback: (Boolean) -> Unit
    ) {
        DialogHelper.showDialog(
            context,
            title = "权限申请",
            content = "光环助手将向您申请开启设备的应用列表权限，以保证能正常使用相关功能。拒绝授权将无法正常使用部分功能。",
            cancelText = "放弃",
            confirmText = "去授权",
            cancelClickCallback = null,
            confirmClickCallback = { requestGetInstalledAppsListPermission(context, false, resultCallback) },
            extraConfig = DialogHelper.Config(hint = HINT_CHECK_USAGE),
            uiModificationCallback = {
                it.hintTv.setTextColor(ContextCompat.getColor(context, R.color.text_theme))
                it.hintTv.setOnClickListener {
                    val provider = TheRouter.get(IDirectProvider::class.java)
                    provider?.directToWebView(context, Constants.PERMISSION_SCENARIO_ADDRESS, "(权限弹窗)")
                }
                it.contentTv.setTextColor(ContextCompat.getColor(context, R.color.text_primary))
            }
        )
    }

    /**
     * 检查添加到桌面快捷方式权限
     */
    @SuppressLint("CheckResult")
    @JvmStatic
    fun checkShortcutPermission(
        context: FragmentActivity,
        onGrantedCallback: EmptyCallback,
        onDeniedCallback: EmptyCallback
    ) {
        tryWithDefaultCatch {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                onGrantedCallback.onCallback()
                return
            }
            val rxPermission = RxPermissions(context)
            rxPermission
                .requestEachCombined(
                    Manifest.permission.INSTALL_SHORTCUT,
                    Manifest.permission.UNINSTALL_SHORTCUT,
                )
                .subscribe { permission ->
                    when {
                        permission.granted -> {
                            onGrantedCallback.onCallback()
                        }

                        permission.shouldShowRequestPermissionRationale -> {
                            // do nothing
                        }

                        else -> {
                            onDeniedCallback.onCallback()
                        }
                    }
                }
        }
    }

    fun checkCalendarPermissions(
        fragment: Fragment,
        gameId: String,
        gameName: String,
        gameType: String,
        block: () -> Unit
    ) {
        val context = fragment.context ?: return
        val activity = fragment.activity ?: return
        val permissions = arrayOf(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR)
        val hasPermission = permissions.all {
            context.checkCallingOrSelfPermission(it) == PackageManager.PERMISSION_GRANTED
        }
        if (hasPermission) {
            block()
        } else {
            var isDismissByUser = false
            val dialog = Dialog(context, R.style.NoAnimationDialog)
            val binding =
                DialogCalendarPermissionBinding.inflate(LayoutInflater.from(context))
            dialog.setContentView(binding.root)
            dialog.show()
            dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
            dialog.window?.setLayout(
                (context.resources.displayMetrics.widthPixels - 60F.dip2px()),
                WindowManager.LayoutParams.WRAP_CONTENT
            )
            dialog.setOnDismissListener {
                if (!isDismissByUser) {
                    SensorsBridge.trackCalendarPermissionsDialogClick("关闭弹窗", gameId, gameName, gameType)
                }
            }

            binding.tvCancel.setOnClickListener {
                isDismissByUser = true
                SensorsBridge.trackCalendarPermissionsDialogClick("暂不授权", gameId, gameName, gameType)
                dialog.dismiss()
            }
            binding.tvSubmit.setOnClickListener {
                isDismissByUser = true
                SensorsBridge.trackCalendarPermissionsDialogClick("开启权限", gameId, gameName, gameType)
                dialog.dismiss()

                val descriptionDialog = showCalendarPermissionDescriptionDialog(activity)
                val shouldShowRequestPermissionRationale =
                    permissions.any(fragment::shouldShowRequestPermissionRationale)
                if (shouldShowRequestPermissionRationale) {
                    showPermissionPermanentlyDeniedDialog(
                        activity = activity,
                        permissionName = R.string.calendar_permission.toResString(),
                        0.4F
                    ) {
                        descriptionDialog.dismiss()
                    }
                } else {
                    requestCalendarPermission(gameId, gameName, gameType, descriptionDialog, activity, block)
                }

            }

            SensorsBridge.trackCalendarPermissionsDialogShow(gameId, gameName, gameType)
        }
    }

    @SuppressLint("CheckResult")
    private fun requestCalendarPermission(
        gameId: String,
        gameName: String,
        gameType: String,
        descriptionDialog: Dialog,
        activity: FragmentActivity,
        block: () -> Unit
    ) {
        RxPermissions(activity)
            .requestEachCombined(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR)
            .subscribe { permission ->
                when {
                    permission.granted -> {
                        descriptionDialog.dismiss()
                        SensorsBridge.trackCalendarPermissionsDialogResult(true, gameId, gameName, gameType)
                        block()
                    }

                    permission.shouldShowRequestPermissionRationale -> {
                        // do nothing
                        descriptionDialog.dismiss()
                        SensorsBridge.trackCalendarPermissionsDialogResult(false, gameId, gameName, gameType)
                    }

                    else -> {
                        SensorsBridge.trackCalendarPermissionsDialogResult(false, gameId, gameName, gameType)
                        showPermissionPermanentlyDeniedDialog(
                            activity = activity,
                            permissionName = R.string.calendar_permission.toResString()
                        ) {
                            descriptionDialog.dismiss()
                        }
                    }
                }
            }
    }

    private fun showCalendarPermissionDescriptionDialog(activity: FragmentActivity): Dialog {
        val dialog = Dialog(activity, R.style.NoAnimationDialog)

        val binding = DialogExternalStoragePermissionIntroBinding.inflate(LayoutInflater.from(activity))

        val spannableBuilder =
            SpannableStringBuilder("当您使用APP时，在以下场景向您请求日历权限，用于帮助您将游戏上线提醒写入日历：\n")

        val liStringList = arrayListOf(
            "游戏预约”开启“日历提醒"
        )

        for (li in liStringList) {
            val liSpanned = SpannableStringBuilder(li).apply {
                setSpan(
                    ImprovedBulletSpan(bulletRadius = 1.5F.dip2px(), gapWidth = 14F.dip2px()),
                    0,
                    li.length,
                    Spanned.SPAN_INCLUSIVE_EXCLUSIVE
                )
            }
            spannableBuilder.append(liSpanned)
        }

        binding.contentTv.text = spannableBuilder
        binding.titleTv.text = "权限使用说明"

        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setContentView(binding.root)
        dialog.window?.setGravity(Gravity.TOP)
        dialog.window?.setDimAmount(0.4F)
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        dialog.show()
        return dialog
    }

}