package com.gh.common.util

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.getMetaExtra
import com.gh.gamecenter.common.utils.isSimulatorGame
import com.gh.gamecenter.common.utils.asVGame
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SpeedUtils
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus

object DownloadNotificationHelper {

    private const val DOWNLOAD_GROUP_KEY = "download_group_key"
    private const val DOWNLOAD_CHANNEL_ID = "download"
    private const val DOWNLOAD_NOTIFICATION_FOLD_ID = 889
    private const val DOWNLOAD_NOTIFICATION_ID = 888
    private const val PROGRESS_MAX = 100

    const val ACTION_INSTALL = "com.gh.gamecenter.INSTALL"
    const val ACTION_DOWNLOAD = "com.gh.gamecenter.DOWNLOAD"
    const val ACTION_VDOWNLOAD = "com.gh.gamecenter.VDOWNLOAD"

    private val mNotifyMap: MutableMap<String, Long> by lazy { mutableMapOf() }

    private fun getNotificationManager(): NotificationManager {
        return HaloApp.getInstance().application.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    }

    @JvmStatic
    @Synchronized
    fun addOrUpdateDownloadNotification(entity: DownloadEntity) {
        var requireUpdateNotificationGroupDelay = false
        val notificationManager = getNotificationManager()
        val downloadNotificationId = (entity.gameId + entity.packageName).hashCode()
        val xapkStatus = entity.meta[XapkInstaller.XAPK_UNZIP_STATUS]

        if (entity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.SILENT_UPDATE) return
        if (entity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.SIMULATOR_DOWNLOAD) return

        val intent = Intent()
        if (entity.status == DownloadStatus.done && xapkStatus != XapkUnzipStatus.FAILURE.name) {
            intent.putExtra(EntranceConsts.KEY_URL, entity.url)
            intent.putExtra(EntranceConsts.KEY_PATH, entity.path)
            intent.action = ACTION_INSTALL
        } else if (entity.asVGame()) {
            intent.action = ACTION_VDOWNLOAD
        } else {
            intent.action = ACTION_DOWNLOAD
        }
        tryCatchInRelease {
            val pendingIntent = PendingIntent.getBroadcast(
                HaloApp.getInstance().application,
                downloadNotificationId,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT
            )

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                val channel =
                    NotificationChannel(DOWNLOAD_CHANNEL_ID, DOWNLOAD_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW)
                notificationManager.createNotificationChannel(channel)
            }

            val whenTime = 1000 * 60 * (System.currentTimeMillis() / 1000 / 60)
            val builder = NotificationCompat.Builder(HaloApp.getInstance().application, DOWNLOAD_CHANNEL_ID)
                .setContentTitle(entity.name)
                .setSmallIcon(getNotificationIcon())
                .setContentIntent(pendingIntent)
                .setGroup(DOWNLOAD_GROUP_KEY)
                .setWhen(whenTime)

            if (xapkStatus == XapkUnzipStatus.FAILURE.name) {
                builder.setContentText("《" + entity.name + "》解压失败，点击查看详情~")
            } else {
                when (entity.status) {
                    DownloadStatus.downloading -> builder.setContentText(
                        String.format(
                            "%s(剩%s)",
                            SpeedUtils.getSpeed(entity.speed),
                            SpeedUtils.getRemainTime(entity.size, entity.progress, entity.speed * 1024)
                        )
                    )
                    DownloadStatus.done -> builder.setContentText("下载完成，点击立即安装")
                    DownloadStatus.waiting -> builder.setContentText("等待中")
                    DownloadStatus.subscribe,
                    DownloadStatus.timeout,
                    DownloadStatus.diskisfull,
                    DownloadStatus.diskioerror,
                    DownloadStatus.neterror -> builder.setContentText("已暂停，连接WiFi自动下载")
                    else -> builder.setContentText("暂停中")
                }
                builder.setProgress(PROGRESS_MAX, entity.percent.toInt(), false)
            }

            when (entity.status) {
                DownloadStatus.done -> {
                    builder.setSortKey("A")
                    builder.setOngoing(true) // 垃圾华为 sortKey 不起效 priority 也不起效，要将下载完成任务的通知置顶只能设置为 ongoing，喷了
                }
                DownloadStatus.downloading -> builder.setSortKey("B")
                else -> builder.setSortKey("C")
            }

            val notification = builder.build() // 可能会抛出异常
            notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
            if (xapkStatus == XapkUnzipStatus.FAILURE.name) {
                notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
            } else {
                notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
            }

            if (entity.status == DownloadStatus.delete
                || entity.status == DownloadStatus.cancel
                || entity.status == DownloadStatus.hijack
                || entity.status == DownloadStatus.unqualified
                || entity.status == DownloadStatus.unavailable
                || entity.status == DownloadStatus.banned
                || entity.status == DownloadStatus.uncertificated
                || entity.status == DownloadStatus.notfound
                || entity.status == DownloadStatus.overflow
                || (entity.status == DownloadStatus.done // 触发安装事件以后也 cancel 掉通知
                        && !entity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION].isNullOrEmpty()
                        && xapkStatus != XapkUnzipStatus.FAILURE.name)
                || entity.status == DownloadStatus.done && entity.isSimulatorGame()
            ) {//模拟器游戏下载完需要cancel掉通知
                requireUpdateNotificationGroupDelay = true
                notificationManager.cancel(entity.path, DOWNLOAD_NOTIFICATION_ID)
            } else {
                if (entity.status != DownloadStatus.downloading) {
                    notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
                } else {
                    val time = mNotifyMap[entity.path]
                    val curTime = System.currentTimeMillis()
                    if (time == null || curTime - time > 2000) {
                        mNotifyMap[entity.path] = curTime
                        notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
                    }
                }
            }
        }

        if (requireUpdateNotificationGroupDelay) {
            // 虽然运行到这里时 notification 已经被 cancel 了，但在下面的 notificationManager.getActiveNotifications 里它有可能还是 active 状态,
            // 这里延时 100 ms 避免出现所有的任务都取消了以后依旧有一条 notification group 常驻
            AppExecutor.uiExecutor.executeWithDelay(Runnable { updateNotificationGroup() }, 100)
        } else {
            updateNotificationGroup()
        }
    }

    private fun updateNotificationGroup() {
        // 部分华为设备调用 getActiveNotifications() 方法时会触发方法内的空指针，这里整体包裹处理了
        tryCatchInRelease {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                val notificationManager = getNotificationManager()
                val activeNotifications = notificationManager.activeNotifications
                var downloadNotificationSize = 0
                var downloadGroupNotificationSize = 0
                for (activeNotification in activeNotifications) {
                    if (activeNotification.id == DOWNLOAD_NOTIFICATION_ID) {
                        downloadNotificationSize++
                    }
                    if (activeNotification.id == DOWNLOAD_NOTIFICATION_FOLD_ID) {
                        downloadGroupNotificationSize++
                    }
                }

                if (downloadNotificationSize == 0 && downloadGroupNotificationSize != 0) {
                    // 删除组可能会把组内所有通知一并删除
                    notificationManager.cancel(DOWNLOAD_NOTIFICATION_FOLD_ID)
                } else if (downloadNotificationSize != 0 && downloadGroupNotificationSize == 0) {
                    val groupBuilder =
                        NotificationCompat.Builder(HaloApp.getInstance().application, DOWNLOAD_CHANNEL_ID)
                            .setSmallIcon(getNotificationIcon())
                            .setGroup(DOWNLOAD_GROUP_KEY)
                            .setGroupSummary(true)
                            .setStyle(NotificationCompat.BigTextStyle().bigText("下载任务"))
                    val groupNotification = groupBuilder.build()
                    groupNotification.flags = groupNotification.flags or Notification.FLAG_NO_CLEAR
                    notificationManager.notify(DOWNLOAD_NOTIFICATION_FOLD_ID, groupNotification)
                }
            }
        }
    }

    private fun getNotificationIcon(): Int {
        return com.gh.gamecenter.common.R.mipmap.logo
    }
}