package com.gh.common.util

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.gh.common.dialog.InstallPermissionDialogFragment
import com.gh.common.xapk.XapkInstaller
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.getMetaExtra
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.vpn.VpnHelper
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.FileUtils
import com.lightgame.utils.Utils
import java.io.File

object PackageInstaller {

    /**
     * 为了兼容java代码
     */
    @JvmStatic
    fun install(context: Context, downloadEntity: DownloadEntity?) {
        downloadEntity?.let { install(context, downloadEntity, true) }
    }

    /**
     * 启动安装应用程序并取消通知栏安装消息
     *
     * 兼容所有包安装(apk,xapk),后续可加上apks
     *
     * 主动点击安装如果是xapk则需要toast提示
     */
    @JvmStatic
    fun install(context: Context, downloadEntity: DownloadEntity, showUnzipToast: Boolean) {
        val pkgPath = downloadEntity.path
        val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()
        val isVGame = downloadEntity.getMetaExtra(Constants.SMOOTH_GAME) == "true"

        val currentActivity = CurrentActivityHolder.getCurrentActivity() ?: return

        if (isVGame) {
            VHelper.install(currentActivity, downloadEntity)
            return
        }

        // 已知问题
        // 1. 此处可能遇到 activity 是 WXEntryActivity，因为 WXEntryActivity 不是 AppCompatActivity 调不起弹窗
        // 2. 当 activity 全部出栈，但是应用还在下载游戏，下载完会唤不起安装
        if (currentActivity is AppCompatActivity && !currentActivity.isFinishing) {
            InstallPermissionDialogFragment.show(currentActivity, downloadEntity) { isFromPermissionGrantedCallback ->
                // 取消状态栏下载完成的通知，若存在
                downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
                DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)

                // 安卓12后的设备，需要重启应用来继续解压 XAPK 文件
                if (isFromPermissionGrantedCallback && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    val pm = context.packageManager
                    val intent = pm.getLaunchIntentForPackage(context.packageName)
                    val mainIntent = Intent.makeRestartActivityTask(intent!!.component)
                    context.startActivity(mainIntent)
                    Runtime.getRuntime().exit(0)
                } else {
                    if (isXapk) {
                        XapkInstaller.install(context, downloadEntity, showUnzipToast)
                    } else {
                        install(context, downloadEntity.isPlugin, downloadEntity.path, downloadEntity)
                    }
                }
            }
        }
    }

    /**
     * 启动安装应用程序
     *
     * 除非特殊情况,请勿使用此方法进行应用安装操作
     * 除非你已经确定该文件一定是Apk
     *
     * @param downloadEntity 仅用来记录日志用，非必须可为空
     */
    @JvmStatic
    fun install(context: Context, isPluggin: Boolean = false, pkgPath: String?, downloadEntity: DownloadEntity? = null) {
        if (pkgPath.isNullOrEmpty()) {
            ToastUtils.toast("下载文件异常")
            return
        }

        try {
            // 判断是否需要使用浏览器来进行安装
            if (BrowserInstallHelper.isUseBrowserToInstallEnabled()
                && BrowserInstallHelper.shouldUseBrowserToInstall()
            ) {
                BrowserInstallHelper.downloadFile(pkgPath)
                return
            }

            if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
                val currentActivity = CurrentActivityHolder.getCurrentActivity()

                if (VpnHelper.shouldUseVpn() && currentActivity is AppCompatActivity) {
                    turnOnVpnThenInstall(currentActivity, pkgPath, downloadEntity)
                } else {
                    install(context, pkgPath)
                }
            } else {
                if (isPluggin) {
                    DialogHelper.showPluginDialog(context) {
                        uninstall(context, pkgPath)
                    }
                } else {
                    // 非插件化的同包名不同签名冲突
                    DialogHelper.showSignatureConflictDialog(context) {
                        uninstall(context, pkgPath)
                    }
                }
            }
        } catch (e: Exception) {
            Utils.toast(context, e.message)
        }
    }

    /**
     * 最终执行安装的方法
     */
    private fun install(context: Context, pkgPath: String) {
        HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
        val installIntent = getInstallIntent(context, pkgPath)
        context.startActivity(installIntent)
    }

    /**
     * 获取启动安装意图
     *
     * 除非特殊情况,请勿使用此方法进行应用安装操作
     * 除非你已经确定该文件一定是Apk且该次安装无需检查签名情况
     */
    @JvmStatic
    fun getInstallIntent(context: Context, path: String): Intent {
        var uri = Uri.fromFile(File(path))
        val installIntent =
            if (BrowserInstallHelper.isUseBrowserToInstallEnabledWithPackageMatched()) {
                Intent(Intent.ACTION_INSTALL_PACKAGE)
            } else {
                Intent(Intent.ACTION_VIEW)
            }
        if ("smartisan" == Build.MANUFACTURER) {
            installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, File(path))
            installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
            installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        } else {
            // 应用内更新不加 FLAG_ACTIVITY_NEW_TASK 在模拟器上会出现安装完成后安装界面也一并消失的类似闪退的表现
            // Application 上下文就更不用说了
            val pkgName = PackageUtils.getPackageNameByPath(context, path)
            if (pkgName == context.packageName || context !is Activity) {
                installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
        }
        InstallUtils.getInstance()
            .addInstall(PackageUtils.getPackageNameByPath(context, path))
        return installIntent
    }

    /**
     * 卸载应用
     */
    @JvmStatic
    fun uninstall(context: Context, path: String) {
        // TODO 根据 path 获取包名可能出现获取不到的情况，看能不能改成直接用包名！
        val packageName = PackageUtils.getPackageNameByPath(context, path)
        uninstallForPackageName(context, packageName)
    }

    /**
     * 根据包名卸载应用
     */
    @JvmStatic
    fun uninstallForPackageName(context: Context, pkn: String?) {
        if (pkn.isNullOrEmpty()) return

        val uninstallIntent = Intent()
        uninstallIntent.action = Intent.ACTION_DELETE
        uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT)
        if (context !is Activity) {
            uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        uninstallIntent.data = Uri.parse("package:$pkn")
        InstallUtils.getInstance().addUninstall(pkn)
        context.startActivity(uninstallIntent)
    }

    @JvmStatic
    fun getDownloadPathWithId(id: String, format: String?): String {
        return FileUtils.getDownloadPath(
            HaloApp.getInstance().application,
            id + "." + getFileSuffixByFormat(format)
        )
    }

    private fun getFileSuffixByFormat(format: String?): String {
        return if (format == XapkInstaller.XAPK_EXTENSION_NAME) {
            XapkInstaller.XAPK_EXTENSION_NAME
        } else {
            "apk"
        }
    }

    @JvmStatic
    fun createDownloadId(gameName: String?): String {
        return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis())
    }

    /**
     * 启动 VPN 然后安装应用 （若没有授权会先提醒授权 VPN ，若拒绝授权会回落到直接执行安装）
     */
    private fun turnOnVpnThenInstall(currentActivity: AppCompatActivity,
                                     pkgPath: String,
                                     downloadEntity: DownloadEntity?) {
        if (VpnHelper.isVpnPermissionGranted(currentActivity) == true) {
            VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
                if (shouldShowVpnError) {
                    ToastUtils.toast("安装防护功能启动失败")
                }
                install(currentActivity, pkgPath)
            }
        } else {
            val isTheFirstTimeToShowVpnHintDialog = VpnHelper.isTheFistTimeToShowVpnHintDialog()

            downloadEntity?.let {
                NewFlatLogUtils.logVpnHintDialogShow(it.gameId, it.name)
            }

            // 将 VPN 提示弹窗标记为已读（已读后的下一次显示"不再提醒"按钮）
            VpnHelper.setVpnHintDialogShowed()
            if (!VpnHelper.shouldShowVpnHintDialog()) {
                VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
                    if (shouldShowVpnError) {
                        ToastUtils.toast("安装防护功能启动失败")
                    }
                    install(currentActivity, pkgPath)
                }
            } else {
                DialogHelper.showGuideDialog(
                    context = currentActivity,
                    title = "开启安装防护",
                    content = "建议您开启安装防护功能，该功能有助于帮助您更快的完成安装，避免因提示和置换导致的重复下载等问题，安装防护功能需要获取您的VPN权限",
                    confirmText = "立即授权开启防护",
                    cancelText = "不再提醒",
                    confirmClickCallback = {
                        VpnHelper.ignoreVpnHintDialog()
                        VpnHelper.startVpn(currentActivity) { shouldShowVpnError ->
                            if (shouldShowVpnError) {
                                ToastUtils.toast("安装防护功能启动失败")
                            }
                            install(currentActivity, pkgPath)
                        }

                        downloadEntity?.let {
                            NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "立即授权")
                        }
                    },
                    cancelClickCallback = {
                        VpnHelper.ignoreVpnFunction()
                        install(currentActivity, pkgPath)
                        downloadEntity?.let {
                            NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "不再提醒")
                        }
                    },
                    extraConfig = DialogHelper.Config(
                        showCloseIcon = true,
                        showAlternativeCancelStyle = !isTheFirstTimeToShowVpnHintDialog
                    ),
                    uiModificationCallback = { binding, dialog ->
                        binding.cancelTv.visibility = View.GONE
                        binding.closeContainer.setOnClickListener {
                            install(currentActivity, pkgPath)
                            dialog.dismiss()

                            downloadEntity?.let {
                                NewFlatLogUtils.logVpnHintDialogClick(it.gameId, it.name, "关闭按钮")
                            }
                        }
                    }
                )
            }
        }
    }

}