package com.gh.ndownload.suspendwindow

import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.View
import com.gh.common.util.DirectUtils
import com.gh.common.util.PackageInstaller
import com.gh.download.DownloadManager
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.manager.PackagesManager
import com.gh.ndownload.NDataChanger
import com.gh.ndownload.suspendwindow.data.NDownloadState
import com.gh.ndownload.suspendwindow.utils.NDownloadSuspendWindowHelper
import com.gh.ndownload.suspendwindow.view.NDownloadSuspendIconLayout
import com.gh.ndownload.suspendwindow.view.NDownloadSuspendIconView
import com.gh.ndownload.suspendwindow.window.NDownloadSuspendCloseWindow
import com.gh.ndownload.suspendwindow.window.NDownloadSuspendIconWindow
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode

/**
 * 下载悬浮窗-控制器
 */
class NDownloadSuspendWindowController(private val application: Application) :
    NDownloadSuspendIconLayout.OnDragCallback, Application.ActivityLifecycleCallbacks,
    PackageInstaller.OnInstallListener, NDownloadSuspendIconView.OnIconClickListener {

    private var isStarted = false

    private var closeTriggered = false

    private var downloadCount: Int = 0

    private var currentDownloadEntity: DownloadEntity? = null

    private val closeWindow: NDownloadSuspendCloseWindow = NDownloadSuspendCloseWindow(application)

    private val iconWindow: NDownloadSuspendIconWindow = NDownloadSuspendIconWindow(application)

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

    fun show() {
        if (isStarted) return

        isStarted = true
        onAttachToUi()
        trackInstallSuspendedWindowDialogFirstShow()
        initCurrentDownloadEntity()
        NDataChanger.addObserver(downloadObserver)
        PackageInstaller.registerOnInstallListener(this)
        EventBus.getDefault().register(this)
        application.registerActivityLifecycleCallbacks(this)
    }

    fun dismiss() {
        if (!isStarted) return

        downloadCount = 0
        currentDownloadEntity = null
        NDataChanger.deleteObserver(downloadObserver)
        PackageInstaller.unregisterOnInstallListener(this)
        EventBus.getDefault().unregister(this)
        application.unregisterActivityLifecycleCallbacks(this)
        onDetachFromUi()
        isStarted = false
    }

    private fun onAttachToUi() {
        closeWindow.attach()
        iconWindow.attach()
        iconWindow.setOnDragCallback(this)
        iconWindow.setOnIconClickListener(this)
    }

    private fun onDetachFromUi() {
        iconWindow.setOnDragCallback(null)
        iconWindow.setOnIconClickListener(null)
        closeWindow.detach()
        iconWindow.detach()
    }

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

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

    private fun initCurrentDownloadEntity(): Boolean =
        findPriorityDownloadEntity()?.let { downloadEntity ->
            getIconDownloadState(downloadEntity)?.let {
                updateDownloadEntityAndState(downloadEntity, it)
                true
            }
        } ?: false

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

    private fun isHigherPriorDownloadEntity(downloadEntity: DownloadEntity): Boolean =
        NDownloadSuspendWindowHelper.isIconDownloadPriorityHigher(downloadEntity, currentDownloadEntity)

    private fun shouldSkipDownloadEntity(downloadEntity: DownloadEntity): Boolean =
        NDownloadSuspendWindowHelper.shouldSkipDownloadEntity(application, downloadEntity)

    private fun calculateDownloadCount(): Int =
        NDownloadSuspendWindowHelper.calculateDownloadCount(application)

    private fun calculateDoneCount(): Int =
        NDownloadSuspendWindowHelper.calculateDoneCount(application)

    private fun findPriorityDownloadEntity(): DownloadEntity? =
        NDownloadSuspendWindowHelper.findPriorDownloadEntityFromDownloadList(application)

    private fun getIconDownloadState(downloadEntity: DownloadEntity): NDownloadState? =
        NDownloadSuspendWindowHelper.getIconDownloadState(downloadEntity)


    private fun updateDownloadEntityAndState(downloadEntity: DownloadEntity, downloadState: NDownloadState) {
        this.currentDownloadEntity = downloadEntity
        iconWindow.setDownloadIconUrl(downloadEntity.icon ?: "")
        iconWindow.setDownloadState(downloadState)
    }

    private fun jumpToDownloadManagerCenter(context: Context) {
        if (!GlobalActivityManager.isAppForeground()
            || GlobalActivityManager.currentActivity !is DownloadManagerActivity
        ) {
            DirectUtils.directToDownloadManager(context, "下载悬浮窗")
        }
    }

    private fun jumpToInstall(context: Context) {
        val currentDownloadEntity = this.currentDownloadEntity
        if (currentDownloadEntity != null) {
            if (GlobalActivityManager.isAppForeground()) {
                PackageInstaller.install(context, currentDownloadEntity)
            } else {
                val intent = Intent().apply {
                    data = Uri.parse("ghzhushou://install?package_name=${currentDownloadEntity.packageName}")
                    action = Intent.ACTION_VIEW
                    addCategory(Intent.CATEGORY_DEFAULT)
                    addCategory(Intent.CATEGORY_BROWSABLE)
                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                }
                context.startActivity(intent)
            }
        }
    }

    override fun onDragStart(v: View) {
        closeWindow.show()
    }

    override fun onDragMove(v: View, x: Float, y: Float) {
        // 判断悬浮图标位置是否处于关闭按钮中
        closeTriggered = closeWindow.checkTouchPoint(x, y)
        if (closeTriggered) {
            closeWindow.scaleUp()
        } else {
            closeWindow.scaleDown()
        }
    }

    override fun onDragEnd(v: View, x: Float, y: Float) {
        if (closeTriggered) {// 关闭显示悬浮图标
            dismiss()
            closeTriggered = false
        } else {
            closeWindow.hide()
        }
    }


    /**
     *     根据游戏下载相关回调，更新悬浮窗状态：
     *     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 (shouldSkipDownloadEntity(downloadEntity)) return

        val status = downloadEntity.status

        if (status == DownloadStatus.add || status == DownloadStatus.subscribe || status == DownloadStatus.download) {
            val currentDownloadEntity = this.currentDownloadEntity
            // 当前downloadEntity状态为download/add/subscribe，只有downloadEntity为空的情况需要更新UI
            if (currentDownloadEntity == null) {
                updateDownloadEntityAndState(
                    downloadEntity,
                    NDownloadState.Downloading(0)
                )
            }
            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的创建时间
            if (isHigherPriorDownloadEntity(downloadEntity) || isCurrentDownloadEntity(downloadEntity)) {
                updateDownloadEntityAndState(
                    downloadEntity,
                    NDownloadSuspendWindowHelper.getIconInstallState(downloadEntity)
                )
            }
            initDownloadCount()
            return
        }

        if (status == DownloadStatus.cancel) {
            if (isCurrentDownloadEntity(downloadEntity)
                && !PackagesManager.isInstalled(downloadEntity.packageName)
                && !initCurrentDownloadEntity()) {// 安装完成也会回调一个cancel事件，但是不需要在这里进行处理，所以需要过滤掉
                dismiss()
            }
            initDownloadCount()
            return
        }

        if (status == DownloadStatus.delete) {
            // 当前任务被删除并且当前任务列表中无符合显示悬浮窗的下载任务，关闭悬浮窗显示
            if (isCurrentDownloadEntity(downloadEntity) && !initCurrentDownloadEntity()) {
                dismiss()
            } else {
                initDownloadCount()
            }
            return
        }

        if (status == DownloadStatus.downloading
            && (isHigherPriorDownloadEntity(downloadEntity) || isCurrentDownloadEntity(downloadEntity))
        ) {
            updateDownloadEntityAndState(
                downloadEntity,
                NDownloadState.Downloading(downloadEntity.percent.toInt())
            )
            return
        }

        if (status == DownloadStatus.pause && isCurrentDownloadEntity(downloadEntity)) {
            initCurrentDownloadEntity()
            return
        }
    }

    private fun trackInstallSuspendedWindowDialogFirstShow() {
        if (!NDownloadSuspendWindowHelper.isDownloadSuspendWindowFirstShown()) {
            val source = NDownloadSuspendWindowHelper.getDownloadSuspendWindowFirstShownSource()
            SensorsBridge.trackDownloadSuspendedWindowResultReturn(source)
            NDownloadSuspendWindowHelper.markDownloadSuspendWindowFirstShown()
        }
    }

    /**
     * 畅玩/本地应用安装中回调处理
     */
    override fun onInstalling(packageName: String?, packagePath: String) {
        if (packageName.isNullOrEmpty()) return

        val downloadEntity = DownloadManager
            .getInstance()
            .getDownloadEntityByPackageName(packageName) ?: return

        if (isCurrentDownloadEntity(downloadEntity)) {
            iconWindow.setDownloadState(NDownloadState.Installing)
        } else if (!shouldSkipDownloadEntity(downloadEntity) && isHigherPriorDownloadEntity(downloadEntity)) {
            updateDownloadEntityAndState(downloadEntity, NDownloadState.Installing)
        }
    }

    /**
     * 安装完成的回调处理
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onInstalled(event: EBPackage) {
        if (!isStarted || event.type == EBPackage.TYPE_UNINSTALLED) {
            return
        }

        val currentDownloadEntity = this.currentDownloadEntity ?: return

        // 当所有任务流程都执行完成以后，则显示“完成”状态，否则显示下一个优先级最高的任务
        if (calculateDoneCount() <= 1 && event.packageName == currentDownloadEntity.packageName) {
            iconWindow.setDownloadState(NDownloadState.Complete)
        } else if (!initCurrentDownloadEntity()) {
            dismiss()
        }
    }

    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit

    override fun onActivityStarted(activity: Activity) = Unit

    override fun onActivityPostResumed(activity: Activity) = Unit

    override fun onActivityResumed(activity: Activity) {
        if (!isStarted) return

        val currentDownloadEntity = this.currentDownloadEntity ?: return
        // 从安装界面返回光环应用内，需要把安装中的状态重置为“去安装”
        if (currentDownloadEntity.status == DownloadStatus.done
            && !PackagesManager.isInstalled(currentDownloadEntity.packageName)
        ) {
            iconWindow.setDownloadState(NDownloadState.Install)
        }
    }
    override fun onActivityPaused(activity: Activity) = Unit

    override fun onActivityStopped(activity: Activity) = Unit

    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit

    override fun onActivityDestroyed(activity: Activity) = Unit
    override fun onIconClick(v: View, downloadState: NDownloadState?) {
        when (downloadState) {
            NDownloadState.Install -> jumpToInstall(v.context)
            NDownloadState.Complete -> {
                dismiss()
                jumpToDownloadManagerCenter(v.context)
            }

            NDownloadState.Pause,
            is NDownloadState.Downloading,
            NDownloadState.Installing -> jumpToDownloadManagerCenter(v.context)

            else -> {}
        }
    }
}