package com.gh.download

import android.content.pm.PackageInfo
import android.text.TextUtils
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.exposure.meta.MetaUtil.getMeta
import com.gh.gamecenter.common.loghub.LoghubUtils
import com.gh.common.util.*
import com.gh.common.xapk.XapkInstaller
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.getMetaExtra
import com.gh.gamecenter.common.utils.isSimulatorGame
import com.gh.gamecenter.common.utils.DeviceUtils
import com.halo.assistant.HaloApp
import com.lightgame.download.DataChanger
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import com.lightgame.utils.Utils
import org.json.JSONArray
import org.json.JSONObject

object DownloadDataHelper {
    private const val DOWNLOAD_SPEED_TIME = "download_speed_time"
    private const val DOWNLOAD_SPEED_SIZE = "download_speed_size"

    const val DOWNLOAD_RESUME_WAY = "download_resume_way"
    const val DOWNLOAD_RESUME_MANUAL = "manual"
    const val DOWNLOAD_RESUME_AUTO = "auto"

    const val DOWNLOAD_CANCEL_WAY = "download_cancel_way"
    const val DOWNLOAD_CANCEL_MANUAL = "manual"
    const val DOWNLOAD_CANCEL_AUTO = "auto"

    const val DOWNLOAD_FIRST_START = "download_first_start"

    private val mDownloadSpeedMap = HashMap<String, MutableList<Long>>()

    private val mDownloadHeartbeatList = mutableListOf<JSONObject>()
    private val mDownloadHeartbeatSheet = HashMap<String, JSONObject>()

    @JvmStatic
    fun getDownloadStatusAlias(downloadEntity: DownloadEntity, downloadStatus: DownloadStatus? = null): String {
        val status = downloadStatus ?: downloadEntity.status
        return if (status == DownloadStatus.add) {
            "开始下载"
        } else if (status == DownloadStatus.pause) {
            "暂停下载"
        } else if (status == DownloadStatus.resume) {
            if (downloadEntity.meta[DOWNLOAD_RESUME_WAY] == DOWNLOAD_RESUME_AUTO) {
                "自动恢复下载"
            } else {
                "继续下载"
            }
        } else if (status == DownloadStatus.waiting) {
            "暂停下载-等待中"
        } else if (status == DownloadStatus.subscribe || status == DownloadStatus.neterror || status == DownloadStatus.timeout) {
            "暂停下载-连上WiFi自动下载"
        } else if (status == DownloadStatus.done) {
            if (downloadEntity.isSimulatorGame()) {
                return "下载完成"
            }
            val packageInfo = if (PackageUtils.isDeviceUnableToHandleBigApkFile(downloadEntity.path)) {
                PackageInfo()
            } else {
                val pm = HaloApp.getInstance().application.applicationContext.packageManager
                pm.getPackageArchiveInfo(downloadEntity.path, 0)
            }
            if (packageInfo == null && XapkInstaller.PACKAGE_EXTENSION_NAME == downloadEntity.path.getExtension()) {
                "解析包错误"
            } else {
                "下载完成"
            }
        } else if (status == DownloadStatus.delete || status == DownloadStatus.cancel) {
            if (downloadEntity.meta[DOWNLOAD_CANCEL_WAY] == DOWNLOAD_CANCEL_AUTO) {
                "自动删除任务"
            } else {
                "删除任务"
            }
        } else if (status == DownloadStatus.overflow) {
            "解析包错误-下载过程中"
        } else if (status == DownloadStatus.hijack || status == DownloadStatus.notfound) {
            "下载失败"
        } else if (status == DownloadStatus.uncertificated) {
            "未实名"
        } else if (status == DownloadStatus.unqualified) {
            "未成年"
        } else if (status == DownloadStatus.unavailable) {
            "未接入防沉迷系统，暂不支持下载"
        } else if (status == DownloadStatus.banned) {
            "网络异常"
        } else if (status == DownloadStatus.redirected) {
            "重定向至最终地址"
        } else {
            "未知状态"
        }
    }

    fun uploadRedirectEvent(downloadEntity: DownloadEntity) {
        val jsonObject = JSONObject()

        try {
            jsonObject.put("event", "download_redirect")
            val startupStatus = downloadEntity.meta[DownloadEntity.DOWNLOAD_STARTUP_STATUS_KEY]
            if (startupStatus != null) {
                jsonObject.put("msg", getDownloadStatusAlias(downloadEntity, DownloadStatus.valueOf(startupStatus)))
            }

            jsonObject.put("meta", getMetaJson())
            jsonObject.put("timestamp", System.currentTimeMillis() / 1000)

            // payload
            val payloadObject = JSONObject()
            payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
            payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
            payloadObject.put("game_id", downloadEntity.gameId)
            payloadObject.put("gameName", downloadEntity.name)
            payloadObject.put("platform", downloadEntity.platform)
            payloadObject.put("package", downloadEntity.packageName)
            payloadObject.put("filename", getFileName(downloadEntity))
            jsonObject.put("payload", payloadObject)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        if (BuildConfig.DEBUG) {
            Utils.log("LogUtils->$jsonObject")
        }
        LoghubUtils.log(jsonObject, "download_debug", false)
    }

    @JvmStatic
    fun uploadDownloadEvent(downloadEntity: DownloadEntity) {
        if (downloadEntity.status != DownloadStatus.downloading) {
            uploadDownloadStatusEvent(downloadEntity)
        }

        if (downloadEntity.status == DownloadStatus.downloading) {
            val startupTime = downloadEntity.meta[DownloadEntity.DOWNLOAD_STARTUP_TIME_KEY]
            if (startupTime != null) {
                uploadDownloadStartupTimeEvent(downloadEntity, startupTime.toInt())
                downloadEntity.meta.remove(DownloadEntity.DOWNLOAD_STARTUP_TIME_KEY)
                DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
            }
        }

        if (downloadEntity.status == DownloadStatus.downloading || downloadEntity.status == DownloadStatus.done) {
            val time = downloadEntity.meta[DOWNLOAD_SPEED_TIME]
            val size = downloadEntity.meta[DOWNLOAD_SPEED_SIZE]
            if (downloadEntity.speed == 0L || time == null || size == null) {
                downloadEntity.meta[DOWNLOAD_SPEED_TIME] = System.currentTimeMillis().toString()
                downloadEntity.meta[DOWNLOAD_SPEED_SIZE] = downloadEntity.progress.toString()
                DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
            } else {
                val offset = System.currentTimeMillis() - time.toLong()
                if (offset > 5000) {
                    //记录并重置
                    val downloadedSize = downloadEntity.progress - size.toLong()
                    val averageSpeed = downloadedSize / offset
                    val speedList = mDownloadSpeedMap[downloadEntity.url]
                    if (speedList == null) {
                        mDownloadSpeedMap[downloadEntity.url] = arrayListOf(averageSpeed)
                    } else {
                        speedList.add(averageSpeed)
                        if (speedList.size >= 6 || downloadEntity.status == DownloadStatus.done) {
                            uploadDownloadAverageSpeed(downloadEntity, speedList)
                            if (downloadEntity.status == DownloadStatus.done) {
                                mDownloadSpeedMap.remove(downloadEntity.url)
                            } else {
                                speedList.clear()
                            }
                        }
                    }
                    downloadEntity.meta[DOWNLOAD_SPEED_TIME] = System.currentTimeMillis().toString()
                    downloadEntity.meta[DOWNLOAD_SPEED_SIZE] = downloadEntity.progress.toString()
                    DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
                }
            }
        }
    }

    private fun uploadDownloadStartupTimeEvent(downloadEntity: DownloadEntity, startupTime: Int) {
        val jsonObject = JSONObject()

        try {
            jsonObject.put("event", "下载线程启动")
            val startupStatus = downloadEntity.meta[DownloadEntity.DOWNLOAD_STARTUP_STATUS_KEY]
            if (startupStatus != null) {
                jsonObject.put("msg", getDownloadStatusAlias(downloadEntity, DownloadStatus.valueOf(startupStatus)))
            }

            jsonObject.put("meta", getMetaJson())
            jsonObject.put("timestamp", System.currentTimeMillis() / 1000)

            // payload
            val payloadObject = JSONObject()
            payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
            payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
            payloadObject.put("game_id", downloadEntity.gameId)
            payloadObject.put("gameName", downloadEntity.name)
            payloadObject.put("platform", downloadEntity.platform)
            payloadObject.put("package", downloadEntity.packageName)
            payloadObject.put("filename", getFileName(downloadEntity))
            payloadObject.put("launch_ms", startupTime)
            jsonObject.put("payload", payloadObject)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        if (BuildConfig.DEBUG) {
            Utils.log("LogUtils->$jsonObject")
        }
        LoghubUtils.log(jsonObject, "download_debug", false)
    }

    private fun uploadDownloadStatusEvent(downloadEntity: DownloadEntity) {
        val jsonObject = JSONObject()

        try {
            jsonObject.put("event", getDownloadStatusAlias(downloadEntity))
            jsonObject.put("msg", downloadEntity.error)
            jsonObject.put("status", downloadEntity.status.status)

            jsonObject.put("meta", getMetaJson())
            jsonObject.put("timestamp", System.currentTimeMillis() / 1000)

            // payload
            val payloadObject = JSONObject()
            payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
            payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
            payloadObject.put("game_id", downloadEntity.gameId)
            payloadObject.put("gameName", downloadEntity.name)
            payloadObject.put("platform", downloadEntity.platform)
            payloadObject.put("package", downloadEntity.packageName)
            payloadObject.put("filename", getFileName(downloadEntity))
            payloadObject.put("total_size", downloadEntity.size / 1024 / 1024)
            payloadObject.put("completed_size", downloadEntity.progress / 1024 / 1024)
            if (downloadEntity.status == DownloadStatus.resume) {
                if (downloadEntity.meta[DOWNLOAD_FIRST_START] == "YES") {
                    payloadObject.put("is_first_start", true)
                } else {
                    payloadObject.put("is_first_start", false)
                }
            }

            if (downloadEntity.status == DownloadStatus.resume || downloadEntity.status == DownloadStatus.add) {
                downloadEntity.meta[DOWNLOAD_FIRST_START] = "NO"
                DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
            }
            jsonObject.put("payload", payloadObject)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        if (BuildConfig.DEBUG) {
            Utils.log("LogUtils->$jsonObject")
        }
        LoghubUtils.log(jsonObject, "download_debug", false)
    }


    private fun uploadDownloadAverageSpeed(downloadEntity: DownloadEntity, averageSpeedList: List<Long>) {
        val jsonObject = JSONObject()

        try {
            jsonObject.put("event", "下载进度")
            jsonObject.put("msg", "")

            jsonObject.put("meta", getMetaJson())
            jsonObject.put("timestamp", System.currentTimeMillis() / 1000)

            // payload
            val payloadObject = JSONObject()
            payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
            payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
            payloadObject.put("game_id", downloadEntity.gameId)
            payloadObject.put("gameName", downloadEntity.name)
            payloadObject.put("platform", downloadEntity.platform)
            payloadObject.put("package", downloadEntity.packageName)
            payloadObject.put("filename", getFileName(downloadEntity))
            payloadObject.put("speed_progress", JSONArray(averageSpeedList))
            payloadObject.put("is_finished", downloadEntity.status == DownloadStatus.done)
            jsonObject.put("payload", payloadObject)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        if (BuildConfig.DEBUG) {
            Utils.log("LogUtils->$jsonObject")
        }
        LoghubUtils.log(jsonObject, "download_debug", false)
    }

    /**
     * 分片检测下载进度,每隔15秒内记录一次,60秒上传一次
     *
     * 请见:https://gitlab.ghzs.com/stats/stats-issues/-/issues/188#note_66919
     */
    fun uploadDownloadHeartbeat(upload: Boolean) {
        val allDownloadEntity = DownloadManager.getInstance().allDownloadEntity
        for (downloadEntity in allDownloadEntity) {

            /**
             * 在后台唤醒的情况下 下载状态可能无法修正
             * see [DownloadManager.initDownloadService]
             */
            if (downloadEntity.status == DownloadStatus.downloading && DataChanger.downloadingTasks[downloadEntity.url] != null) {
                var sheet = mDownloadHeartbeatSheet[downloadEntity.url]
                if (sheet == null) {
                    sheet = JSONObject()
                    sheet.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
                    sheet.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
                    sheet.put("game_id", downloadEntity.gameId)
                    sheet.put("platform", downloadEntity.platform)
                    sheet.put("package", downloadEntity.packageName)
                    sheet.put("filename", getFileName(downloadEntity))
                    sheet.put("total_size", downloadEntity.size / 1024 / 1024)
                    sheet.put("current_progress_size", downloadEntity.progress / 1024)
                    mDownloadHeartbeatSheet[downloadEntity.url] = sheet
                } else {
                    val progressSize = sheet.getLong("current_progress_size")
                    sheet.put(
                        "host",
                        downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown"
                    ) // 初始化记录的 host 为空
                    sheet.put(
                        "path",
                        downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown"
                    ) // 初始化记录的 path 为空
                    sheet.put("total_size", downloadEntity.size / 1024 / 1024) // 初始化记录的 total_size 有可能为0
                    sheet.put("progress_size", downloadEntity.progress / 1024 - progressSize)
                    sheet.put("current_progress_size", downloadEntity.progress / 1024)
                    mDownloadHeartbeatList.add(JSONObject(sheet.toString()))
                }
            } else {
                mDownloadHeartbeatSheet.remove(downloadEntity.url)
            }
        }

        if (upload && mDownloadHeartbeatList.isNotEmpty()) {
            val jsonObject = JSONObject()
            try {
                jsonObject.put("event", "progress")
                jsonObject.put("meta", getMetaJson())
                jsonObject.put("timestamp", System.currentTimeMillis() / 1000)

                val payloads = JSONArray()
                for (heartbeatData in mDownloadHeartbeatList) {
                    heartbeatData.remove("current_progress_size")
                    payloads.put(heartbeatData)
                }
                jsonObject.put("payloads", payloads)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            if (BuildConfig.DEBUG) {
                Utils.log("LogUtils->$jsonObject")
            }
            mDownloadHeartbeatList.clear()
            LoghubUtils.log(jsonObject, "download_debug", false)
        }
    }

    private fun getMetaJson(): JSONObject {
        val context = HaloApp.getInstance().application
        val meta = getMeta()
        // meta
        val metaObject = JSONObject()
        metaObject.put("dia", MetaUtil.getBase64EncodedAndroidId())
        metaObject.put("android_sdk", meta.android_sdk)
        metaObject.put("android_version", meta.android_version)
        metaObject.put("appVersion", meta.appVersion)
        metaObject.put("channel", meta.channel)
        metaObject.put("gid", meta.gid)
        metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI())
        metaObject.put("mac", meta.mac)
        metaObject.put("manufacturer", meta.manufacturer)
        metaObject.put("model", meta.model)
        metaObject.put("network", DeviceUtils.getNetwork(context))
        metaObject.put("os", meta.os)
        metaObject.put("MNC", "")
        metaObject.put("userId", meta.userId)
        return metaObject
    }

    private fun getFileName(downloadEntity: DownloadEntity): String {
        val downloadId = downloadEntity.getMetaExtra(Constants.DOWNLOAD_ID)
        return if (!TextUtils.isEmpty(downloadId)) {
            downloadId + downloadEntity.path.substring(downloadEntity.path.lastIndexOf("."))
        } else {
            downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1)
        }
    }
}