package com.gh.download.simple

import android.annotation.SuppressLint
import com.gh.gamecenter.core.utils.ToastUtils
import com.lg.download.*
import com.lg.download.listener.InnerDownloadListener
import com.lg.ndownload.DownloadConfig
import java.net.URLConnection
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.ArrayList

/**
 * 下载信息管理类
 */
object DownloadMessageHandler : InnerDownloadListener {

    // 单页可订阅的监听数最少从 3 开始, 如果值为 5 的话有可能出现状态无法更新的情况 (fragment onDestroy 回调慢)
    private const val MAX_LISTENER_SIZE = 5

    private lateinit var mDownloadDao: DownloadDao

    private val mGlobalStatusChangedListenerList by lazy {
        arrayListOf<((SimpleDownloadEntity, DownloadStatus) -> Unit)>()
    }

    /**
     * map key: 下载 id
     *
     * map value:
     *     pair first-> 下载实体
     *     pair second-> 对应页面的下载回调
     */
    private var mListenerMap: ConcurrentHashMap<String, FixedSizeStack<DownloadListener>> = ConcurrentHashMap()

    var downloadList = arrayListOf<SimpleDownloadEntity>()

    @SuppressLint("CheckResult")
    fun init(downloadDao: DownloadDao) {
        mDownloadDao = downloadDao

        updateDownloadList()
    }

    /**
     * 注册全局回调（为避免影响下载性能，目前仅对接了状态变更回调）
     */
    fun registerGlobalStatusChangedListener(listener: ((SimpleDownloadEntity, DownloadStatus) -> Unit)) {
        mGlobalStatusChangedListenerList.add(listener)
    }

    /**
     * 状态回调
     * @param id 下载 id
     * @param status 下载状态
     */
    override fun onStatusChanged(id: String, status: DownloadStatus) {
        val entity = findEntity(id)

        if (entity != null) {
            entity.status = status

            if (status == DownloadStatus.COMPLETED) {
                SimpleDownloadManager.resumeQueuedTask()
            }

            ExecutorProvider.getInstance().backgroundExecutor.execute {
                updateDownloadToDatabase(entity)
                updateDownloadList()
            }
        }

        for (listener in mGlobalStatusChangedListenerList) {
            listener.invoke(entity!!, status)
        }

        val listenerList = mListenerMap[id] ?: return

        ExecutorProvider.getInstance().mainThreadExecutor.execute {
            safeIteratorList(listenerList) {
                it.onStatusChanged(status)
            }
        }
    }

    /**
     * 重定向中的回调
     * @param id 下载 id
     * @param connection 未重定向前的原始连接
     * @param config 下载配置
     */
    override fun onRedirectingUrl(id: String?, connection: URLConnection?, config: DownloadConfig?) {

    }

    /**
     * 重定向完成后的回调
     * @param id 下载 id
     * @param connection 重定向完成后的连接
     * @param redirectedUrl 重定向完成的最终地址
     */
    override fun onRedirectedUrl(id: String, connection: URLConnection, redirectedUrl: String) {
        val entity = findEntity(id) ?: return

        entity.url = redirectedUrl

        // 更新数据库数据
        updateDownloadToDatabase(entity, updateDownloadList = true)
    }

    /**
     * 进度回调，带频率控制，适合用来更新 UI
     * @param id 下载 id
     * @param progress 进度 0~1
     */
    override fun onProgress(id: String, progress: Float) {
        val entity = findEntity(id) ?: return

        entity.progress = progress * 100

        updateDownloadToDatabase(entity)

        val listenerList = mListenerMap[id] ?: return

        ExecutorProvider.getInstance().mainThreadExecutor.execute {
            safeIteratorList(listenerList) {
                it.onProgress(progress * 100)
            }
        }

        updateDownloadList()
    }

    /**
     * 没有频率控制的进度回调，适合做一些轻度的操作
     * @param id 下载 id
     * @param progress 进度 0~1
     */
    override fun onProgressWithoutThrottle(id: String?, progress: Float) {

    }

    /**
     * 速度回调，带频率控制，适合用来更新 UI
     * @param id 下载 id
     * @param speed 下载速度，单位为字节
     */
    override fun onSpeedChanged(id: String, speed: Float) {
        val listenerList = mListenerMap[id] ?: return

        ExecutorProvider.getInstance().mainThreadExecutor.execute {
            safeIteratorList(listenerList) {
                it.onSpeedChanged(speed)
            }
        }

        findEntity(id)?.run {
            this.speed = speed
        }
    }

    /**
     * 错误回调
     * @param id 下载 id
     * @param error 错误类型
     * @param exception 包裹错误的 Exception
     */
    override fun onError(id: String, error: DownloadError?, exception: Exception) {
        error ?: return

        when (error) {
            DownloadError.EMPTY_URL,
            DownloadError.HTTP_NOT_FOUND,
            DownloadError.CONTENT_LENGTH_IS_ZERO -> {
                ToastUtils.toast("下载链接异常，请检查")
            }
            else -> {
                // 想怎么处理就怎么处理
            }
        }

        val listenerList = mListenerMap[id] ?: return

        ExecutorProvider.getInstance().mainThreadExecutor.execute {
            safeIteratorList(listenerList) {
                it.onError(error)
            }
        }
    }

    /**
     * 文件大小获取成功回调
     * @param id 下载 id
     * @param fileSize 文件大小，单位为字节
     */
    override fun onSizeReceived(id: String, fileSize: Long) {
        val entity = findEntity(id) ?: return

        entity.totalBytes = fileSize
        updateDownloadToDatabase(entity, updateDownloadList = true)

        val listenerList = mListenerMap[id] ?: return

        ExecutorProvider.getInstance().mainThreadExecutor.execute {
            safeIteratorList(listenerList) {
                it.onSizeReceived(fileSize)
            }
        }

        updateDownloadList()
    }

    fun registerListener(id: String, listener: DownloadListener) {
        var listenerList = mListenerMap[id]
        if (listenerList == null) {
            listenerList = FixedSizeStack(MAX_LISTENER_SIZE)
            listenerList.push(listener)
            mListenerMap[id] = listenerList
        } else {
            listenerList.push(listener)
        }

        // Post download status if it could be obtain from database.
        val entityFromDatabase = findEntity(id)
        if (entityFromDatabase != null) {
            listener.onProgress(entityFromDatabase.progress)
            listener.onStatusChanged(entityFromDatabase.status)
        }
    }

    fun unregisterListener(id: String, listener: DownloadListener) {
        ExecutorProvider.getInstance().mainThreadExecutor.execute {
            mListenerMap[id]?.remove(listener)
        }
    }

    /**
     * 从下载列表中取 downloadEntity
     * TODO 不应该直接修改 downloadEntity 内存的值，不然会有莫名其妙的问题
     */
    fun findEntity(id: String): SimpleDownloadEntity? {
        try {
            return downloadList.firstOrNull { it.id == id }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    private fun updateDownloadList() {
        downloadList = ArrayList(mDownloadDao.getAllDownloadEntity())
    }

    fun insertDownloadToDatabase(downloadEntity: SimpleDownloadEntity) {
        mDownloadDao.insertDownloadEntity(downloadEntity)
        updateDownloadList()
    }

    fun updateDownloadToDatabase(
        downloadEntity: SimpleDownloadEntity,
        updateDownloadList: Boolean = false
    ) {
        mDownloadDao.updateDownloadEntity(downloadEntity)

        if (updateDownloadList) {
            updateDownloadList()
        }
    }

    fun deleteDownloadOfDatabase(downloadEntity: SimpleDownloadEntity) {
        mDownloadDao.deleteDownloadEntity(downloadEntity)
        updateDownloadList()
    }

    /*****
     * 迭代的时候针对temp Stack进行迭代
     */
    private fun safeIteratorList(
        sourceList: FixedSizeStack<DownloadListener>?,
        function: (arg: DownloadListener) -> (Unit)
    ) {
        sourceList?.apply {
            if (this.size > 0) {
                // FIXME 高频遍历时会产生巨量临时的 FixedSizeStack
                val tempStack = FixedSizeStack<DownloadListener>(MAX_LISTENER_SIZE)

                tempStack.addAll(sourceList)

                tempStack.forEach { listener ->

                    listener?.apply {
                        function(this)
                    }
                }
            }
        }
    }
}