package com.gh.download.server

import android.content.Context
import android.os.Build
import android.util.Base64
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.ExposureEntity
import com.gh.gamecenter.common.loghub.LoghubUtils
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.core.utils.GsonUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.google.gson.JsonObject
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.net.URLEncoder
import java.util.*

object BrowserInstallHelper {

    // 随便选的 32321 居然在部分 vivo 手机上被占用，喷了
    private const val PORT = 40705
    private const val RESERVE_PORT = 40706

    private lateinit var mServer: DownloadServer
    private val mFileNameSet by lazy { hashSetOf<String>() }
    private val mContext by lazy { HaloApp.getInstance().application }
    private var mUseReservePort = false

    private val mAllInstalledPackageList: ArrayList<String> by lazy {
        PackageUtils.getAllPackageNameIncludeSystemApps(HaloApp.getInstance().applicationContext).apply {
            add(HaloApp.getInstance().applicationContext.packageName)
        }
    }

    private fun getServer(port: Int): DownloadServer {
        val server = DownloadServer(port)
        for (packageName in mAllInstalledPackageList) {
            if (packageName.contains("com.freeme") || packageName.contains("com.zhuoyi")) {
                server.isBuggyDevice = true
                break
            }
        }
        return server
    }

    fun downloadFile(filePath: String) {
        if (!::mServer.isInitialized) mServer = if (mUseReservePort) getServer(RESERVE_PORT) else getServer(PORT)
        if (!mServer.isAlive && !startServer()) {
            // 端口占用时使用备用端口重试
            mUseReservePort = true
            mServer = getServer(RESERVE_PORT)
            if (!mServer.isAlive) retryStartServer()
        }

        var fileName = filePath.substringAfterLast(File.separator)
        // 山寨机没有 .apk 后缀但有 Content-Type 管用，还是给它补上 .apk 后缀
        if (!mServer.isBuggyDevice) {
            fileName = fileName.removeSuffix(DownloadServer.APK_SUFFIX)
        }
        val downloadUrl =
            if (mUseReservePort) "http://127.0.0.1:$RESERVE_PORT/$fileName" else "http://127.0.0.1:$PORT/$fileName"

        mFileNameSet.add(fileName)
        if (mServer.isBuggyDevice) {
            val encodedString =
                Base64.encodeToString(URLEncoder.encode(downloadUrl).trim().toByteArray(), Base64.NO_WRAP)
            DirectUtils.directToExternalBrowser(
                mContext,
                "https://down-and.ghzs.com/redirect?location=base64($encodedString)"
            )
        } else {
            DirectUtils.directToExternalBrowser(mContext, downloadUrl)
        }
    }

    @JvmStatic
    fun shouldUseBrowserToInstall(): Boolean {
        if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
            return true
        }

        return false
    }

    /**
     * 是否显示使用浏览器来安装弹窗
     */
    private fun shouldShowUseBrowserToInstallHint(): Boolean {
        return if (isUseBrowserToInstallEnabled()) {
            if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
                false
            } else {
                SPUtils.getBoolean(Constants.SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT, true)
            }
        } else {
            false
        }
    }

    /**
     * 是否显示游戏详情页使用浏览器安装提示
     */
    fun shouldShowGameDetailUseBrowserToInstallHint(): Boolean {
        return if (isUseBrowserToInstallEnabled()) {
//            if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
//                false
//            } else {
            SPUtils.getBoolean(Constants.SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT, true)
//            }
        } else {
            false
        }
    }

    fun hideGameDetailUseBrowserToInstallHint() {
        SPUtils.setBoolean(Constants.SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT, false)
    }

    @JvmStatic
    fun showBrowserInstallHintDialog(
        context: Context,
        skipBrowserInstallDialog: Boolean = false,
        callback: EmptyCallback
    ) {
        if (skipBrowserInstallDialog || !shouldShowUseBrowserToInstallHint()) {
            callback.onCallback()
            return
        }

        logOrdinaryBrowserEvent(Type.SWITCH_INSTALL_DIALOG)
        SPUtils.setBoolean(Constants.SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT, false)

        val manufacturer = Build.MANUFACTURER.toUpperCase(Locale.CHINA)
        var contentText = "当前安装方式为助手安装，如果出现游戏无法安装的问题，可选择切换安装方式为“浏览器安装”"
        if (manufacturer == "OPPO" || manufacturer == "VIVO") {
            contentText = "当前安装方式为助手安装，下载安装游戏需要验证账户密码或指纹。如需免密码安装，可选择切换安装方式为“浏览器安装”"
        }

        DialogHelper.showDialog(
            context,
            title = "温馨提示",
            content = contentText,
            confirmText = "切换安装方式",
            cancelText = "继续下载",
            confirmClickCallback = {
                val intent = ShellActivity.getIntent(context, ShellActivity.Type.SWITCH_INSTALL_METHOD, null)
                context.startActivity(intent)
                logOrdinaryBrowserEvent(Type.SWITCH_INSTALL_DIALOG_ACCESS)
            },
            cancelClickCallback = {
                callback.onCallback()
                logOrdinaryBrowserEvent(Type.SWITCH_INSTALL_DIALOG_QUIT)
            },
            extraConfig = DialogHelper.Config(hint = "修改路径：我的光环-设置-切换安装方式")
        )
    }

    /**
     * 浏览器安装的后台开关
     */
    @JvmStatic
    fun isUseBrowserToInstallEnabled(): Boolean {
        val settingsEntity = Config.getNewSettingsEntity()

        if (settingsEntity == null) {
            return false
        } else {
            if (settingsEntity.installModel?.status == "matched") {
                return true
            }
            settingsEntity.installModel?.whiteList?.let {
                for (packageName in it) {
                    if (mAllInstalledPackageList.contains(packageName)) {
                        return false
                    }
                }
            }
            settingsEntity.installModel?.packages?.let {
                for (packageName in it) {
                    if (mAllInstalledPackageList.contains(packageName)) {
                        return true
                    }
                }
            }

            return false
        }
    }

    /**
     * 浏览器安装的后台开关 (返回仅包名匹配时的状态)
     */
    @JvmStatic
    fun isUseBrowserToInstallEnabledWithPackageMatched(): Boolean {
        val settingsEntity = Config.getNewSettingsEntity()

        if (settingsEntity == null) {
            return false
        } else {
            settingsEntity.installModel?.whiteList?.let {
                for (packageName in it) {
                    if (mAllInstalledPackageList.contains(packageName)) {
                        return false
                    }
                }
            }
            settingsEntity.installModel?.packages?.let {
                for (packageName in it) {
                    if (mAllInstalledPackageList.contains(packageName)) {
                        return true
                    }
                }
            }

            return false
        }
    }

    fun onApkInstalled(path: String?) {
        path?.let {
            val fileName = path.substringAfterLast(File.separator).removeSuffix(DownloadServer.APK_SUFFIX)
            // 更新下载名称 set，确定是否需要关闭下载服务
            mFileNameSet.remove(fileName)
            stopServerIfNeeded()
        }
    }

    private fun startServer(): Boolean {
        try {
            mServer.start()
        } catch (e: Exception) {
            return false
        }
        return true
    }

    private fun retryStartServer() {
        try {
            mServer.start()
        } catch (e: Exception) {
            e.printStackTrace()
            Utils.toast(mContext, "浏览器下载服务开启失败")
        }
    }

    private fun stopServerIfNeeded() {
        // 下载的文件都下载完了
        if (::mServer.isInitialized && mFileNameSet.size == 0) {
            mServer.stop()
        }
    }

    /**以下为日志相关方法**/
    fun logWebDownloadStarted(exposureEvent: ExposureEvent, downloadId: String, isDownloadComplete: Boolean) {
        val jsonObject = JSONObject()
        tryCatchInRelease {
            jsonObject.put("event", if (isDownloadComplete) "web_download_complete" else "web_download")
            jsonObject.put("payload", exposureEvent2JSONObject(exposureEvent.payload, downloadId))
            jsonObject.put("meta", LogUtils.getMetaObject())
            jsonObject.put("source", JSONArray(GsonUtils.toJson(exposureEvent.source)))
            jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
        }
        Utils.log(jsonObject.toString())
        LoghubUtils.log(jsonObject, "event", false)
    }

    private fun exposureEvent2JSONObject(payload: ExposureEntity, downloadId: String): JSONObject {
        val string = (GsonUtils.gson.toJsonTree(payload) as JsonObject).apply {
            addProperty("uni_filename", "$downloadId${DownloadServer.APK_SUFFIX}")
        }.toString()

        return JSONObject(string)
    }

    fun logOrdinaryBrowserEvent(type: Type) {
        val jsonObject = JSONObject()
        tryCatchInRelease {
            jsonObject.put("event", type.toString().toLowerCase(Locale.CHINA))
            jsonObject.put("meta", LogUtils.getMetaObject())
            jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
        }
        Utils.log(jsonObject.toString())
        LoghubUtils.log(jsonObject, "event", false)
    }

    enum class Type {
        SWITCH_INSTALL_DIALOG,
        SWITCH_INSTALL_DIALOG_QUIT,
        SWITCH_INSTALL_DIALOG_ACCESS,
        SWITCH_INSTALL_GUIDE_ACCESS,
        SWITCH_INSTALL_GUIDE_QUIT,
        SWITCH_INSTALL_SETTING,
        SWITCH_INSTALL_SETTING_APP,
        SWITCH_INSTALL_SETTING_WEB
    }

}