package com.gh.ndownload.suspendwindow.dialog

import android.app.Activity
import android.app.Dialog
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.util.TypedValue
import android.view.*
import android.widget.FrameLayout
import com.gh.common.util.PackageChangeHelper
import com.gh.common.xapk.XapkInstaller
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.isSimulatorDownload
import com.gh.gamecenter.common.utils.isSimulatorGame
import com.gh.gamecenter.manager.PackagesManager
import com.gh.ndownload.NDataChanger
import com.gh.ndownload.suspendwindow.data.NDownloadState
import com.gh.ndownload.suspendwindow.view.NDownloadDrawOverlayPermissionLayout
import com.gh.ndownload.suspendwindow.view.NDownloadSuspendIconLayout
import com.gh.ndownload.suspendwindow.window.NDownloadDrawOverlayPermissionWindow
import com.gh.ndownload.suspendwindow.window.NDownloadSuspendIconWindow
import com.gh.vspace.VHelper
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus

/**
 * 下载引导开启悬浮窗弹窗
 */
class NDownloadDrawOverlayPermissionDialog(activity: Activity) : Dialog(activity) {

    private var isStarted = false

    private var downloadCount: Int = 0

    private var currentDownloadEntity: DownloadEntity? = null

    private val contentWindow: NDownloadDrawOverlayPermissionWindow = NDownloadDrawOverlayPermissionWindow(activity)

    private val iconWindow: NDownloadSuspendIconWindow = NDownloadSuspendIconWindow(activity)

    private lateinit var iconLayout: NDownloadSuspendIconLayout

    private lateinit var contentLayout: NDownloadDrawOverlayPermissionLayout

    private val downloadObserver by lazy {
        object : DataWatcher() {
            override fun onDataChanged(downloadEntity: DownloadEntity?) {
                val download = downloadEntity ?: return
                onDownloadChanged(download)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window?.apply {
            setLayout(
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT
            )
            setBackgroundDrawable(ColorDrawable())
            clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
            attributes.flags =
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        }

        iconLayout = NDownloadSuspendIconLayout(context)
            .also {
                val layoutParams = FrameLayout.LayoutParams(
                    FrameLayout.LayoutParams.WRAP_CONTENT,
                    FrameLayout.LayoutParams.WRAP_CONTENT
                ).apply {
                    gravity = Gravity.CENTER_VERTICAL or Gravity.END
                }
                it.setBackgroundResource(R.drawable.shape_download_suspend_icon_idle_right)
                addContentView(it, layoutParams)
            }

        contentLayout = NDownloadDrawOverlayPermissionLayout(context)
            .also {
                val layoutParams = FrameLayout.LayoutParams(
                    TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP,
                        200F,
                        context.resources.displayMetrics
                    ).toInt(),
                    FrameLayout.LayoutParams.WRAP_CONTENT
                ).apply {
                    gravity = Gravity.CENTER
                }
                addContentView(it, layoutParams)
            }
    }

    override fun onStart() {
        super.onStart()
        window?.setLayout(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.MATCH_PARENT
        )
    }

    fun filterDownloadEntity(downloadEntity: DownloadEntity): Boolean =
        downloadEntity.packageName == context.packageName
                || downloadEntity.packageName == VHelper.DEFAULT_VSPACE_PACKAGENAME
                || downloadEntity.packageName == VHelper.VSPACE_32BIT_PACKAGENAME
                || downloadEntity.path.getExtension() == XapkInstaller.XAPK_EXTENSION_NAME
                || downloadEntity.meta[Constants.EXTRA_DOWNLOAD_TYPE] == Constants.VGAME
                || downloadEntity.meta[Constants.EXTRA_DOWNLOAD_TYPE] == Constants.DUAL_DOWNLOAD_VGAME
                || downloadEntity.isPlugin
                || downloadEntity.isPluggable
                || downloadEntity.isSimulatorDownload()
                || downloadEntity.isSimulatorGame()

    fun start() {
        if (isStarted) return

        isStarted = true
        onAttachToUi()
        initDownloadCount()
        initCurrentDownloadEntity()
        NDataChanger.addObserver(downloadObserver)
    }

    fun stop() {
        if (!isStarted) return

        downloadCount = 0
        currentDownloadEntity = null
        onDetachFromUi()
        NDataChanger.deleteObserver(downloadObserver)
        isStarted = false
    }

    private fun onAttachToUi() {
        contentWindow.attach()
        iconWindow.attach()
    }

    private fun onDetachFromUi() {
        contentWindow.detach()
        iconWindow.detach()
    }

    private fun initDownloadCount() {
        setDownloadCount(calculateDownloadCount())
    }

    private fun calculateDownloadCount(): Int {
        var downloadCount = 0
        val downloadList = DownloadManager
            .getInstance()
            .allDownloadEntityExcludeDoneTask
        for (downloadEntity in downloadList) {
            if (!filterDownloadEntity(downloadEntity)) {
                downloadCount++
            }
        }
        return downloadCount
    }

    private fun setDownloadCount(count: Int) {
        if (this.downloadCount != count) {
            this.downloadCount = count
            iconWindow.setDownloadCount(count)
        }
    }

    private fun initCurrentDownloadEntity(): Boolean =
        findPriorDownloadEntityFromDownloadList()?.let {
            updateCurrentDownloadEntity(it)
            updateDownloadIconAndState(it.icon ?: "", getDownloadState(it))
            true
        } ?: false

    /**
     * 从下载列表中获取悬浮窗最优先显示的游戏实例
     */
    private fun findPriorDownloadEntityFromDownloadList(): DownloadEntity? {
        val downloadList = DownloadManager.getInstance().allDownloadEntity
        if (downloadList.isEmpty()) return null

        var currentDownloadEntity: DownloadEntity? = null
        for (downloadEntity in downloadList) {
            if (filterDownloadEntity(downloadEntity)) {
                continue
            }
            val needToUpdate = currentDownloadEntity == null
                    || (downloadEntity.status == DownloadStatus.done && currentDownloadEntity.status != DownloadStatus.done)
                    || (downloadEntity.status == DownloadStatus.done && getInstallStep(downloadEntity.packageName) > getInstallStep(
                downloadEntity.packageName
            ))
                    || (downloadEntity.start < currentDownloadEntity.start)
            if (needToUpdate) {
                currentDownloadEntity = downloadEntity
            }
        }
        return currentDownloadEntity
    }

    private fun updateCurrentDownloadEntity(downloadEntity: DownloadEntity) {
        this.currentDownloadEntity = downloadEntity
    }

    /**
     * 是否为当前悬浮窗显示的游戏
     */
    private fun isCurrentDownloadEntity(downloadEntity: DownloadEntity): Boolean {
        return this.currentDownloadEntity == downloadEntity || this.currentDownloadEntity?.gameId == downloadEntity.gameId
    }

    private fun updateDownloadIconAndState(iconUrl: String, downloadState: NDownloadState) {
        iconWindow.setDownloadIconUrl(iconUrl)
        iconWindow.setDownloadState(downloadState)
    }


    /**
     *     根据游戏下载相关回调，更新悬浮窗状态：
     *
     *     1）未开启悬浮窗权限时：
     *
     *          a.UI-元素-游戏ICON：展示当前触发权限引导弹窗的游戏ICON
     *
     *          b.UI-元素-下载进度：展示当前触发权限引导弹窗的游戏实际下载进度
     *
     *          c.交互：无法进行交互
     *
     *          d.位置：屏幕右侧居中展示（具体以设计师意见为准）
     *
     *     2）已开启悬浮窗权限时：
     *
     *          a.UI-元素-游戏ICON：
     *
     *               a.-1：用户若触发多个下载任务时，且无任务完成下载进程时，优先展示下载任务创建时间最早的游戏ICON
     *
     *               a.-2：若多个任务中，且无任务完成下载进程，但任务存在被暂停下载/恢复下载时，则恢复下载时，需更新下载任务的创建时间，然后按照创建时间排序进行展示
     *
     *               a.-3：若多个任务中，有任务已经完成下载进程但未进入安装流程，则优先展示已完成下载进程最早的游戏ICON
     *
     *               a.-4：若多个任务中，有任务进入安装流程，则优先展示进入安装流程的游戏ICON
     *
     *               a.-5：若多个任务中，所有任务都完成安装，则优先展示最晚完成安装的游戏ICON
     *
     *          b.UI-元素-游戏数量：
     *
     *               b.-1：用户若触发多个下载任务时，悬浮窗右上角需展示具体的下载中的任务数量
     *
     *               b.-2：当下载任务被删除/游戏完成安装后，悬浮窗右上角的数字则会同步进行减少（当光环助手处于后台，悬浮窗能否进行包名查询确认游戏完成安装）
     *
     *          c.悬浮窗状态及交互逻辑：
     *
     *               c.-1：【下载进度】：点击后唤起光环助手并跳转【下载管理】页面
     *
     *               c.-2：【继续】：点击后唤起光环助手并跳转【下载管理】页面
     *
     *               c.-3：【去安装】：点击后进入对应游戏的安装流程
     *
     *               c.-4：【安装中】：点击后唤起光环助手并跳转【下载管理】页面，并检测游戏是否完成安装并及时更新悬浮窗文案（说明：因游戏处于安装过程中，光环助手处于后台，期间光环助手无法获悉游戏的实际安装状态，当唤起光环助手时则需要通过包名查询确认安装状态，将文案刷新为【去安装】/【完成】/【下载进度】）
     *
     *               c.-5：【完成】：点击后唤起光环助手并跳转【下载管理】页面，并关闭悬浮窗
     *
     *               c.-6：悬浮窗：首次申请后，位于屏幕右侧居中位置；可进行拖动，但仅贴近屏幕两侧，上下不进行贴边；拖动至屏幕底部中央位置可进行悬浮窗的关闭（不同版本系统\机型需要具体适配）
     *
     *          d.安装提示弹窗：
     *
     *               d.-1：弹窗展示时机：游戏完成下载任务时
     *
     *               d.-2：弹窗展示时长：不设置展示时长，由用户主动进行关闭
     *
     *               d.-3：弹窗组件：可参考原先畅玩游戏加载完成提示条逻辑，即多个任务同时完成安装时，使用统一的弹窗组件，只需刷新游戏ICON即可
     *
     *               d.-4：弹窗交互：【关闭】按钮：点击可关闭弹窗（弹窗关闭只能通过点击【关闭】/【安装】/【悬浮窗】才能进行关闭）；【安装】按钮：点击即进入安装流程
     *
     *               d.-5：展示内容：参考原型，以设计图为准
     *
     * @see <a href="https://jira.shanqu.cc/browse/GHZSCY-5389">安装流程相关优化</a>
     */
    private fun onDownloadChanged(downloadEntity: DownloadEntity) {
        if (filterDownloadEntity(downloadEntity)) {
            return
        }

        val status = downloadEntity.status
        if (status == DownloadStatus.add || status == DownloadStatus.subscribe) {
            val currentDownloadEntity = this.currentDownloadEntity
            // 当前downloadEntity状态为add或subscribe，以下情形需要更新UI:
            // 1. currentDownloadEntity为空
            // 2. currentDownloadEntity的状态不为done，并且它的创建时间大于downloadEntity的创建时间
            val needToUpdate = currentDownloadEntity == null
                    || (currentDownloadEntity.status != DownloadStatus.done && currentDownloadEntity.start > downloadEntity.start)
            if (needToUpdate) {
                val installStep = getInstallStep(downloadEntity.packageName)
                updateCurrentDownloadEntity(downloadEntity)
                updateDownloadIconAndState(downloadEntity.icon ?: "", getInstallStateByStep(installStep))
            }
            setDownloadCount(calculateDownloadCount() + 1)// 事件回调的时候下载列表还没有刷新= =，所以不能调用initDownloadCount
            return
        }

        if (status == DownloadStatus.waiting) {
            initDownloadCount()
            return
        }

        if (status == DownloadStatus.done) {
            // 当前downloadEntity状态为done，以下情形需要更新UI:
            // 1. currentDownloadEntity为空
            // 2. currentDownloadEntity的状态不为done
            // 3. currentDownloadEntity的状态为done，但它的创建时间大于downloadEntity的创建时间
            val currentDownloadEntity = this.currentDownloadEntity
            val needToUpdate = currentDownloadEntity == null
                    || currentDownloadEntity.status != DownloadStatus.done
                    || downloadEntity.start < currentDownloadEntity.start
            if (needToUpdate) {
                updateCurrentDownloadEntity(downloadEntity)
                updateDownloadIconAndState(
                    downloadEntity.icon ?: "",
                    getInstallState(downloadEntity)
                )
            }
            initDownloadCount()
            return
        }

        if (status == DownloadStatus.cancel) {
            if (isCurrentDownloadEntity(downloadEntity)) {
                if (PackagesManager.isInstalled(downloadEntity.packageName)) {// 安装成功回调
                    iconWindow.setDownloadState(NDownloadState.Complete)
                } else if (!initCurrentDownloadEntity()) {
                    stop()
                }
            }
            initDownloadCount()
            return
        }

        if (status == DownloadStatus.delete) {
            if (isCurrentDownloadEntity(downloadEntity) && !initCurrentDownloadEntity()) {
                stop()
            }
            initDownloadCount()
            return
        }

        if (status == DownloadStatus.downloading && isCurrentDownloadEntity(downloadEntity)) {
            iconWindow.setDownloadState(NDownloadState.Downloading(downloadEntity.percent.toInt()))
            return
        }

        if (status == DownloadStatus.pause && isCurrentDownloadEntity(downloadEntity)) {
            iconWindow.setDownloadState(NDownloadState.Pause)
            return
        }
    }

    companion object {

        private const val STATE_DONE = 1

        private const val STATE_INSTALLING = 2

        private const val STATE_INSTALLED = 3

        /**
         * 获取当前下载的DownloadState实例
         * @param downloadEntity 当前下载实例
         */
        private fun getDownloadState(downloadEntity: DownloadEntity): NDownloadState = when (downloadEntity.status) {
            DownloadStatus.done -> getInstallState(downloadEntity)
            DownloadStatus.downloading -> NDownloadState.Downloading(downloadEntity.percent.toInt())
            DownloadStatus.download, DownloadStatus.add, DownloadStatus.subscribe, DownloadStatus.waiting -> NDownloadState.Install
            DownloadStatus.cancel -> if (PackagesManager.isInstalled(downloadEntity.packageName)) {
                NDownloadState.Complete
            } else {
                NDownloadState.Pause
            }

            else -> NDownloadState.Pause
        }

        /**
         * 获取当前安装的DownloadState实例
         * @param downloadEntity 当前安装实例
         */
        private fun getInstallState(downloadEntity: DownloadEntity): NDownloadState =
            getInstallStateByStep(getInstallStep(downloadEntity.packageName))

        /**
         * 获取指定应用包名安装进度
         * 1. STATE_DONE - 仅下载完成
         * 2. STATE_INSTALLING - 下载完成并且处于安装中
         * 3. STATE_INSTALLED - 下载完成并且已安装
         */
        private fun getInstallStep(packageName: String): Int =
            if (PackagesManager.isInstalled(packageName)) {
                STATE_INSTALLED
            } else if (PackageChangeHelper.isInstallPendingPackage(packageName)) {
                STATE_INSTALLING
            } else {
                STATE_DONE
            }

        /**
         * 根据安装进度获取DownloadState实例
         * @param installStep 安装进度
         * @return DownloadState实例
         */
        private fun getInstallStateByStep(installStep: Int): NDownloadState = when (installStep) {
            STATE_INSTALLED -> NDownloadState.Complete
            STATE_INSTALLING -> NDownloadState.Installing
            else -> NDownloadState.Install
        }
    }
}