package com.gh.gamecenter.update

import android.content.Context
import android.os.Build
import androidx.core.app.NotificationManagerCompat
import androidx.fragment.app.FragmentActivity
import com.gh.common.exposure.ExposureUtils
import com.gh.common.exposure.ExposureUtils.logADownloadExposureEvent
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.addMetaExtra
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.core.utils.GsonUtils.toJson
import com.gh.gamecenter.entity.AppEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.fragment.UpdateDialogFragment
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.ndownload.NDataChanger
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.AppManager
import com.gh.gamecenter.common.utils.FileUtils
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
import java.io.File
import java.text.SimpleDateFormat
import java.util.*

/**
 * 应用更新的辅助类
 */
object UpdateHelper {

    private const val ONCE_ONLY_SECOND_DEFAULT = "ONCE_ONLY_SECOND_DEFAULT"
    private const val ONCE_ONLY_SECOND_CLOSE = "ONCE_ONLY_SECOND_CLOSE"
    private const val ONCE_ONLY_SECOND_OPEN = "ONCE_ONLY_SECOND_OPEN"

    private const val ALERT_EVERY_TIME_OPEN = "EVERY_TIME_OPEN" // 每次启动都提示
    private const val ALERT_ONCE_ONLY = "ONCE_ONLY" // 仅一次
    private const val ALERT_ONCE_ONLY_SECOND = "ONCE_ONLY_SECOND" // 仅一次（第二次打开）
    private const val ALERT_NEVER = "NEVER" // 从不

    private const val SP_KEY_SHOW_UPDATE_TIME = "show_update_time" // 上次显示更新弹窗的时间

    // 缓存的更新实体
    private var mCachedUpdateEntity: AppEntity? = null
    private val mApi by lazy { RetrofitManager.getInstance().api }
    private val mSp by lazy { HaloApp.getInstance().getSharedPreferences("update", Context.MODE_PRIVATE) }

    private val mVersionName by lazy {
//        "5.12.5-debug"
        PackageUtils.getGhVersionName()
    }

    private val mVersionCode by lazy {
//        410
      PackageUtils.getGhVersionCode()
    }

    /**
     * 检查更新
     * @param dumpCache 是否清除更新的实体缓存 (重新检查更新)
     * @param resultCallback 结果回调，无论成功或失败都会回调，可在此 callback 检查是否有更新
     */
    fun getUpdate(dumpCache: Boolean, resultCallback: EmptyCallback) {
        if (dumpCache) {
            mCachedUpdateEntity = null
        } else if (mCachedUpdateEntity != null) {
            // 若缓存的更新实体不为空，则直接使用缓存的更新实体
            resultCallback.onCallback()
            return
        }

        val channel: String = HaloApp.getInstance().channel
        mApi.getUpdate(mVersionName, mVersionCode, channel, Build.VERSION.SDK_INT)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<AppEntity>() {
                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    resultCallback.onCallback()
                }

                override fun onResponse(response: AppEntity?) {
                    super.onResponse(response)

//                    response?.isForce = true
//                    response?.alert = ALERT_EVERY_TIME_OPEN

                    mCachedUpdateEntity = response

                    resultCallback.onCallback()
                }
            })
    }

    /**
     * 更新是否有效
     * @param ignoreSuppressOption 是否忽略提示
     */
    fun isUpdateValid(ignoreSuppressOption: Boolean): Boolean {
        val updateEntity = mCachedUpdateEntity ?: return false

        if (updateEntity.versionCode >= mVersionCode) {
            if (ignoreSuppressOption || ALERT_EVERY_TIME_OPEN == updateEntity.alert) {
                // 手动检查更新或者后台配置每次启动都提示
                return true
            } else if (ALERT_ONCE_ONLY == updateEntity.alert) {
                // 仅显示一次更新
                if (mSp.getBoolean(getUpdateOnceOnlySpKey(), true)) {
                    return true
                }
            } else if (ALERT_ONCE_ONLY_SECOND == updateEntity.alert) {
                // 仅显示一次更新（第二次打开）
                val onceOnlySecond: String? = mSp.getString(getUpdateOnceOnlySecondSpKey(), ONCE_ONLY_SECOND_DEFAULT)
                if (ONCE_ONLY_SECOND_OPEN == onceOnlySecond) {
                    return true
                }
            } else if (ALERT_NEVER != updateEntity.alert) {  // 一天提示一次
                val showUpdateTime: String? = mSp.getString(SP_KEY_SHOW_UPDATE_TIME, null)
                val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
                val today: String = format.format(Date())
                if (today != showUpdateTime) {
                    return true
                }
            }
        }
        return false
    }

    /**
     * 标记更新的使用情况
     */
    private fun markUpdate(updateEntity: AppEntity) {
        if (ALERT_ONCE_ONLY == updateEntity.alert) {
            // 仅显示一次更新
            mSp.edit().putBoolean(getUpdateOnceOnlySpKey(), false).apply()
        } else if (ALERT_ONCE_ONLY_SECOND == updateEntity.alert) {
            // 仅显示一次更新（第二次打开）
            val onceOnlySecond: String? = mSp.getString(getUpdateOnceOnlySecondSpKey(), ONCE_ONLY_SECOND_DEFAULT)
            if (ONCE_ONLY_SECOND_OPEN == onceOnlySecond) {
                mSp.edit().putString(getUpdateOnceOnlySecondSpKey(), ONCE_ONLY_SECOND_CLOSE).apply()
            }
            if (ONCE_ONLY_SECOND_DEFAULT == onceOnlySecond) {
                mSp.edit().putString(getUpdateOnceOnlySecondSpKey(), ONCE_ONLY_SECOND_OPEN).apply()
            }
        } else if (ALERT_NEVER != updateEntity.alert) {  // 一天提示一次
            val showUpdateTime: String? = mSp.getString(SP_KEY_SHOW_UPDATE_TIME, null)
            val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
            val today: String = format.format(Date())
            if (today != showUpdateTime) {
                mSp.edit().putString(SP_KEY_SHOW_UPDATE_TIME, today).apply()
            }
        }
    }

    /**
     * 显示更新弹窗
     */
    fun showUpdateDialog(activity: FragmentActivity, callback: EmptyCallback) {
        if (mCachedUpdateEntity == null) {
            callback.onCallback()
            return
        }

        UpdateDialogFragment
            .newInstance(mCachedUpdateEntity!!, callback)
            .show(activity.supportFragmentManager, "update")

        markUpdate(mCachedUpdateEntity!!)
    }

    /**
     * 创建下载任务
     */
    fun createUpdate(updateEntity: AppEntity, isSilentUpdate: Boolean) {
        var shouldCancelPreviousDownload = true // 是否应该取消旧更新任务

        // 在部分设备上取消正在进行中的旧下载任务再创建新下载任务有机率造成新下载任务依然带有 "静默更新" 标签导致无法唤起安装
        // 所以这里对当前静默更新任务正在进行中的时候就不用删旧任务，直接改 meta 标签
        if (!isSilentUpdate
            && DownloadManager.getInstance().isTaskDownloading(updateEntity.url)
        ) {
            try {
                val entity = DownloadManager.getInstance().getDownloadEntitySnapshot(updateEntity.url)
                if (entity != null) {
                    entity.addMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE, "不再是静默更新")
                    DownloadManager.getInstance().updateDownloadEntity(entity)
                    DownloadManager.getInstance().resume(entity, false)
                    shouldCancelPreviousDownload = false
                }
            } catch (e: Exception) {
                // 出现异常走删旧下载任务重下流程
                shouldCancelPreviousDownload = true
                e.printStackTrace()
            }
        }

        // 预下载完成或者还没进行预下载的都进这里，先删掉旧的下载文件再进行下载
        if (shouldCancelPreviousDownload) {
            val path = getUpdateDownloadPath(updateEntity)
            val file = File(path)
            if (file.exists() && file.delete()) {
                Utils.log(file.name + " file delete success.")
            }
            val event = logADownloadExposureEvent(
                GameEntity(Constants.GHZS_GAME_ID, "光环助手V" + updateEntity.version),
                null,
                null,
                ExposureUtils.DownloadType.DOWNLOAD
            )
            val downloadEntity = DownloadEntity()
            downloadEntity.url = updateEntity.url
            downloadEntity.name = "光环助手V" + updateEntity.version
            downloadEntity.path = path
            downloadEntity.platform = "官方版"
            downloadEntity.gameId = Constants.GHZS_GAME_ID
            downloadEntity.exposureTrace = toJson(event)
            downloadEntity.format = "apk"
            if (isSilentUpdate) {
                downloadEntity.addMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE, Constants.SILENT_UPDATE)
            }
            downloadEntity.packageName = HaloApp.getInstance().packageName
            DownloadManager.getInstance().cancel(downloadEntity.url, true, true, false)
            DownloadManager.getInstance().pauseAll()
            AppExecutor.uiExecutor.executeWithDelay({
                DownloadManager.getInstance().add(downloadEntity)
            }, 200)
        }
    }

    /**
     * 更新文件是否已下载
     */
    fun isUpdateFileDownloaded(updateEntity: AppEntity): Boolean {
        val file = File(getUpdateDownloadPath(updateEntity))

        return file.exists() && PackageUtils.getPackageNameByPath(HaloApp.getInstance(), file.path) != null
    }

    private fun getUpdateOnceOnlySpKey(): String {
        return "UPDATE_ONCE_ONLY_KEY" + PackageUtils.getGhVersionCode()
    }

    private fun getUpdateOnceOnlySecondSpKey(): String {
        return "UPDATE_ONCE_ONLY_SECOND_KEY" + PackageUtils.getGhVersionCode()
    }

    fun exitApp() {
        NotificationManagerCompat.from(HaloApp.getInstance()).cancelAll()
        AppManager.getInstance().finishAllActivity()
    }

    fun getUpdateDownloadPath(updateEntity: AppEntity): String {
        val md5 = MD5Utils.getUpdateMD5(updateEntity.url, updateEntity.content)

        return FileUtils.getDownloadPath(HaloApp.getInstance(), "光环助手V" + updateEntity.version + "_" + md5 + ".apk")
    }

}