package com.gh.vspace.gapps

import android.animation.ValueAnimator
import android.app.Dialog
import android.os.Build
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.view.View
import android.view.animation.DecelerateInterpolator
import androidx.core.text.bold
import androidx.core.text.color
import com.gh.common.constant.Config
import com.gh.common.util.NewFlatLogUtils
import com.gh.download.simple.*
import com.gh.gamecenter.common.base.fragment.BaseBottomDialogFragment
import com.gh.gamecenter.common.utils.FileUtils
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.core.utils.UnZipUtils
import com.gh.gamecenter.databinding.DialogGappsDownloadBinding
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.vspace.VHelper
import com.lg.download.DownloadError
import com.lg.download.DownloadStatus
import com.lg.download.httpclient.DefaultHttpClient
import com.lg.ndownload.DownloadConfigBuilder
import java.io.File

class GAppsDownloadDialogFragment : BaseBottomDialogFragment<DialogGappsDownloadBinding>() {

    private var mIsInstalling = false // 是否正在安装，避免重复触发
    private var mRequiredAutoInstall = false // 是否需要自动安装（下载完成后自动安装）
    private var mRequiredReTriggerInstall = false // 是否需要重新触发安装（因为切换到后台被中断）
    private var mInstallSuccess = false // 安装是否已经成功
    private var mInstallProgressAnimator: ValueAnimator? = null

    private var mGameId = ""
    private var mGameName = ""
    private var mTriggerPackageName = ""

    private var mGAppsDownloadAndInstallStartTimestampMills = 0L // 谷歌框架下载开始的时间戳
    private var mGAppsDownloadAndInstallElapsedTimeMills = 0L // 谷歌框架下载开始已用的时间（仅下载暂停时记录）

    private val mGAppsUnZipDestPath by lazy {
        requireContext().filesDir.absolutePath + File.separator + "gapps" + File.separator
    }

    private val mGAppsUnZipDestFile by lazy {
        File(mGAppsUnZipDestPath).also { if (!it.exists()) it.mkdir() }
    }

    private val mBatchInstallListener: (isSuccess: Boolean, isInterrupted: Boolean) -> Unit = { isSuccess, isInterrupted ->
        if (isInterrupted) {
            // 安装过程被打断
            mIsInstalling = false
            mRequiredReTriggerInstall = true
        } else {
            val elapsedTime =
                (System.currentTimeMillis() - mGAppsDownloadAndInstallStartTimestampMills + mGAppsDownloadAndInstallElapsedTimeMills) / 1000

            mGAppsDownloadAndInstallStartTimestampMills = 0L
            mGAppsDownloadAndInstallElapsedTimeMills = 0L

            if (isSuccess) {
                showSuccessStyle()
                mInstallSuccess = true
                NewFlatLogUtils.logGAppsInstallSuccess(mGameId, mGameName, elapsedTime.toInt())
                SPUtils.setString(VHelper.G_APPS_INSTALLED_MD5, Config.getVSettingEntity()?.gsf?.md5 ?: "")

                clearCaches()
            } else {
                mInstallSuccess = false
                NewFlatLogUtils.logGAppsInstallFailed(mGameId, mGameName, elapsedTime.toInt())
                resetDownloadStatus(null)
            }
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return super.onCreateDialog(savedInstanceState).also { it.setCanceledOnTouchOutside(false) }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        mGameId = arguments?.getString(GAME_ID) ?: ""
        mGameName = arguments?.getString(GAME_NAME) ?: ""
        mTriggerPackageName = arguments?.getString(TRIGGER_PACKAGE_NAME) ?: ""

        VHelper.registerBatchInstallListener(mBatchInstallListener)

        showDownloadStyle()
        updateViewByDownload(getDownloadEntity())

        AutoUnregisteredSimpleDownloadListener(VHelper.G_APPS_DOWNLOAD_ID, this, object : DownloadListener {
            override fun onError(error: DownloadError) {
                ToastUtils.toast(error.toString())
            }

            override fun onProgress(progress: Float) {
                mBinding.downloadButton.progress = progress.toInt() * 5
                mBinding.downloadButton.showProgress = true
            }

            override fun onSizeReceived(fileSize: Long) {
                // do nothing
            }

            override fun onStatusChanged(status: DownloadStatus) {
                updateViewByDownloadStatus(status)
            }

            override fun onSpeedChanged(speed: Float) {
                // do nothing
            }
        })

        NewFlatLogUtils.logGAppsDialogShowed(mGameId, mGameName)
    }

    override fun onResume() {
        super.onResume()

        // 执行安装重试
        if (mRequiredReTriggerInstall) {
            batchInstall(mGAppsUnZipDestFile)
            mRequiredReTriggerInstall = false
        }
    }

    private fun updateViewByDownload(downloadEntity: SimpleDownloadEntity?) {
        if (downloadEntity != null) {
            updateViewByDownloadStatus(downloadEntity.status)
        } else {
            updateViewByDownloadStatus(DownloadStatus.UNKNOWN)
        }
    }

    private fun updateViewByDownloadStatus(status: DownloadStatus) {
        when (status) {
            DownloadStatus.COMPLETED -> {
                val downloadEntity = getDownloadEntity()

                if (downloadEntity == null) {
                    ToastUtils.toast("下载异常，需要重新下载")
                    SimpleDownloadManager.cancel(VHelper.G_APPS_DOWNLOAD_ID)
                    return
                }

                mBinding.downloadButton.text = "安装中"
                mBinding.downloadButton.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL

                if (mGAppsUnZipDestFile.listFiles()?.size != 3) {
                    // 畅玩功能仅支持 7.1 以后的设备，所以这里的这个判断条件不需要 else
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        runOnIoThread {
                            try {
                                UnZipUtils.unzip(
                                    File(downloadEntity.dirPath + downloadEntity.fileName),
                                    mGAppsUnZipDestPath
                                )

                                var isZipFileValid = mGAppsUnZipDestFile.listFiles()?.size == 3
                                mGAppsUnZipDestFile.listFiles()?.forEach {
                                    if (!it.name.endsWith("apk")) {
                                        isZipFileValid = false
                                    }
                                }

                                if (isZipFileValid) {
                                    batchInstall(mGAppsUnZipDestFile)
                                } else {
                                    SimpleDownloadManager.cancel(VHelper.G_APPS_DOWNLOAD_ID)
                                    resetDownloadStatus(IllegalArgumentException("谷歌框架文件异常，安装失败"))
                                }
                            } catch (e: Exception) {
                                resetDownloadStatus(e)
                            }
                        }
                    }
                } else if (mRequiredAutoInstall && !mIsInstalling) {
                    batchInstall(mGAppsUnZipDestFile)
                }

                mBinding.downloadButton.setOnClickListener {
                    // 处理接口没有返回谷歌框架相关数据的情况
                    if (Config.getVSettingEntity()?.gsf == null || Config.getVSettingEntity()?.gsf?.url == null) {
                        ToastUtils.toast("谷歌框架获取异常，请稍候再试")
                        mBinding.cancelTv.performClick()
                        return@setOnClickListener
                    }

                    if (mInstallSuccess) {
                        VHelper.launch(requireContext(), mTriggerPackageName)
                        NewFlatLogUtils.logGAppsInstalledAndLaunchGame(mGameId, mGameName)
                        dismiss()
                    } else {
                        ToastUtils.toast("正在安装中，请稍候")
                    }
                }
            }

            DownloadStatus.UNKNOWN,
            DownloadStatus.CANCELLED -> {
                mBinding.downloadButton.buttonStyle = DownloadButton.ButtonStyle.NORMAL
                mBinding.downloadButton.text = "安装"
                mBinding.downloadButton.setOnClickListener {
                    val freeSpace = FileUtils.getFreeSpaceByPath(requireContext().filesDir.absolutePath)
                    // 系统少于 600M 可用空间，不允许下载。因为下载要 100M，解压 150M，安装估计也要不少空间
                    if (freeSpace < 600) {
                        ToastUtils.toast("设备存储空间不足，请稍后再试")
                    }

                    NewFlatLogUtils.logGAppsDialogClicked(mGameId, mGameName, "安装")

                    // 记录当前时间戳，供统计最终安装完成耗时用
                    mGAppsDownloadAndInstallStartTimestampMills = System.currentTimeMillis()

                    createDownload()
                    mRequiredAutoInstall = true
                }
            }

            DownloadStatus.DOWNLOADING -> {
                mBinding.downloadButton.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
                mBinding.downloadButton.text = "暂停"
                mBinding.cancelTv.visibility = View.GONE
                mBinding.downloadButton.setOnClickListener {
                    SimpleDownloadManager.pause(VHelper.G_APPS_DOWNLOAD_ID)
                }

                // 恢复下载时更新下载开始时间
                if (mGAppsDownloadAndInstallStartTimestampMills == 0L) {
                    mGAppsDownloadAndInstallStartTimestampMills = System.currentTimeMillis()
                }
            }

            DownloadStatus.AUTOPAUSED,
            DownloadStatus.WAITINGWIFI,
            DownloadStatus.QUEUED,
            DownloadStatus.PAUSED -> {
                mBinding.downloadButton.buttonStyle = DownloadButton.ButtonStyle.LAUNCH_OR_OPEN
                mBinding.downloadButton.text = "继续"

                // 统计暂停时已经用了的下载时长
                mGAppsDownloadAndInstallElapsedTimeMills =
                    System.currentTimeMillis() - mGAppsDownloadAndInstallStartTimestampMills
                mGAppsDownloadAndInstallStartTimestampMills = 0L

                mBinding.downloadButton.setOnClickListener {
                    try {
                        SimpleDownloadManager.resume(VHelper.G_APPS_DOWNLOAD_ID)
                    } catch (e: Exception) {
                        createDownload()
                    }
                }
            }
        }
    }

    /**
     * 创建下载任务
     */
    private fun createDownload() {
        SimpleDownloadManager.download(
            DownloadConfigBuilder()
                .setUniqueId(VHelper.G_APPS_DOWNLOAD_ID)
                .setFileName(VHelper.G_APPS_DOWNLOAD_ID + ".zip")
                .setUrl(Config.getVSettingEntity()?.gsf?.url ?: "")
                .setPathToStore(requireContext().filesDir.absolutePath + File.separator)
                .setHttpClient(DefaultHttpClient())
                .setDownloadThreadSize(2)
                .setDownloadListener(DownloadMessageHandler)
                .setDownloadExecutor(AppExecutor.ioExecutor)
                .build()
        )
    }

    private fun getDownloadEntity(): SimpleDownloadEntity? {
        return DownloadMessageHandler.findEntity(VHelper.G_APPS_DOWNLOAD_ID)
    }

    private fun showSuccessStyle() {
        mInstallProgressAnimator?.end()
        mBinding.downloadButton.progress = 1000
        mBinding.downloadButton.text = "启动游戏"
        mBinding.downloadButton.buttonStyle = DownloadButton.ButtonStyle.LAUNCH_OR_OPEN
        mBinding.successIv.visibility = View.VISIBLE
        mBinding.cancelTv.visibility = View.GONE
        mBinding.descTv1.visibility = View.GONE
        mBinding.descTv2.text = "谷歌框架已安装成功，可启动游戏体验~"
    }

    private fun showDownloadStyle() {
        mBinding.cancelTv.setOnClickListener {
            SimpleDownloadManager.cancel(VHelper.G_APPS_DOWNLOAD_ID)
            NewFlatLogUtils.logGAppsDialogClicked(mGameId, mGameName, "暂不安装")
            VHelper.launch(requireContext(), mTriggerPackageName, true)
            dismiss()
        }
        mBinding.cancelTv.visibility = View.VISIBLE
        mBinding.descTv1.text = SpannableStringBuilder()
            .append("游戏需要安装")
            .bold { color(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext())) { append(" 谷歌框架 ") } }
            .append("后才能稳定运行，为了您的游戏体验，请先安装！")
        mBinding.descTv2.text = "下载过程中请勿退出光环助手，以免影响下载进度，若存在问题请反馈至客服，我们将及时解决"
    }

    /**
     * 批量安装
     */
    private fun batchInstall(destFile: File) {
        val installFileMap = hashMapOf<String, File>()
        destFile.listFiles()?.forEach { installFileMap[it.nameWithoutExtension] = it }

        context?.let {
            mIsInstalling = true
            VHelper.batchInstall(it, installFileMap, mTriggerPackageName)
        }

        runOnUiThread {
            mInstallProgressAnimator = ValueAnimator.ofInt(500, 1000)
            mInstallProgressAnimator?.duration = INSTALL_ANIMATION_DURATION
            mInstallProgressAnimator?.interpolator = DecelerateInterpolator()
            mInstallProgressAnimator?.addUpdateListener {
                mBinding.downloadButton.progress = it.animatedValue as Int
            }
            mInstallProgressAnimator?.start()
        }
    }

    private fun resetDownloadStatus(e: Exception?) {
        // 遇到异常，删除下载任务和解压内容，重新下载
        mGAppsUnZipDestFile.deleteRecursively()
        SimpleDownloadManager.cancel(VHelper.G_APPS_DOWNLOAD_ID)

        runOnUiThread {
            // 重置 UI
            updateViewByDownloadStatus(DownloadStatus.UNKNOWN)
        }
        ToastUtils.toast(e?.localizedMessage ?: "安装失败")
    }

    /**
     * 清理下载、解压缓存
     */
    private fun clearCaches() {
        runOnIoThread {
            SimpleDownloadManager.cancel(VHelper.G_APPS_DOWNLOAD_ID)
            mGAppsUnZipDestFile.deleteRecursively()
        }
    }

    override fun onDestroy() {
        super.onDestroy()

        VHelper.registerBatchInstallListener(null)
    }

    companion object {

        private const val TRIGGER_PACKAGE_NAME = "trigger_package_name" // 触发弹窗的原始游戏包名
        private const val GAME_ID = "game_id"
        private const val GAME_NAME = "game_name"
        private const val INSTALL_ANIMATION_DURATION = 30 * 1000L // 安装动画时长

        fun getInstance(packageName: String, gameId: String, gameName: String): GAppsDownloadDialogFragment {
            return GAppsDownloadDialogFragment().also {
                it.arguments = Bundle().apply {
                    putString(TRIGGER_PACKAGE_NAME, packageName)
                    putString(GAME_ID, gameId)
                    putString(GAME_NAME, gameName)
                }
            }
        }
    }

}