package com.adealink.weparty.commonui.viewmodel

import androidx.lifecycle.LiveData
import com.adealink.frame.base.IError
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.download.listener.TaskListener
import com.adealink.frame.download.task.Task
import com.adealink.frame.log.Log
import com.adealink.frame.mvvm.livedata.OnceMutableLiveData
import com.adealink.frame.mvvm.viewmodel.BaseViewModel
import com.adealink.frame.storage.file.videoPath
import com.adealink.frame.util.ImageUtil
import com.adealink.frame.util.createOrExistsDir
import com.adealink.frame.util.isFileExists
import com.adealink.frame.util.md5
import com.tencent.qgame.animplayer.AnimConfigManager
import com.tencent.qgame.animplayer.file.FileContainer
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import java.io.File
import kotlin.coroutines.resume

data class VapcEffectInfo(
    val remoteUrl: String,
    val localPath: String,
    val width: Int?,
    val height: Int?,
    val duration: Long
) {
    override fun toString(): String {
        return "VapcEffectInfo(url:$remoteUrl, path:$localPath)"
    }
}

abstract class VapcEffectViewModel : BaseViewModel() {

    fun checkAndDownloadEffect(url: String): LiveData<VapcEffectInfo?> {
        val liveData = OnceMutableLiveData<VapcEffectInfo?>()
        viewModelScope.launch {
            liveData.send(
                downloadVideoEffect(url)
            )
        }
        return liveData
    }

    suspend fun downloadVideoEffect(url: String): VapcEffectInfo? {
        val savePath = getSavePath(url)
        return suspendCancellableCoroutine { continuation ->
            addDownloadTask(url, savePath,
                { localPath ->
                    viewModelScope.launch {
                        val vapcEffectInfo = parseEffect(url, localPath)
                        if (continuation.isActive) {
                            continuation.resume(vapcEffectInfo)
                        }
                    }
                },
                {
                    if (continuation.isActive) {
                        continuation.resume(null)
                    }
                })
        }
    }

    suspend fun checkIfNeedDownload(url: String): Boolean {
        val savePath = getSavePath(url)
        return !isFileExists(savePath)
    }

    suspend fun parseEffect(url: String): VapcEffectInfo? {
        return parseEffect(url, getSavePath(url))
    }

    private suspend fun parseEffect(url: String, localPath: String): VapcEffectInfo? {
        return withContext(Dispatcher.WENEXT_THREAD_POOL) {
            if (!isFileExists(localPath)) {
                Log.w(TAG, "parseEffect return, for localPath isn't exists.")
                return@withContext null
            }
            return@withContext try {
                val duration = ImageUtil.getDuration(localPath)
                val vapcInfo = AnimConfigManager.parseVapc(FileContainer(File(localPath)))
                val size = ImageUtil.getVideoSize(localPath)
                VapcEffectInfo(
                    url,
                    localPath,
                    vapcInfo?.width ?: size.first,
                    vapcInfo?.height ?: size.second,
                    duration
                )
            } catch (e: Throwable) {
                Log.w(TAG, "parseEffect return, for parseEffect fail, ${e.message}.")
                null
            }
        }
    }

    private fun addDownloadTask(
        url: String,
        savePath: String,
        success: ((path: String) -> Unit)? = null,
        failed: ((error: IError) -> Unit)? = null,
    ) {
        Log.d(TAG, "addDownloadTask, url: $url")
        Log.d(TAG, "                 savePath: $savePath")
        if (isFileExists(savePath)) {
            Log.d(TAG, "addDownloadTask, fileExist, return")
            success?.invoke(savePath)
            return
        }

        val taskId = url.md5()
        val task = Task(taskId, url, savePath)
        Log.d(
            TAG,
            "addDownloadTask, start download, url:$url, task:$task"
        )
        task.listeners.add(object : TaskListener {

            override fun onFinished(task: Task) {
                super.onFinished(task)
                success?.invoke(savePath)
                Log.d(
                    TAG,
                    "addDownloadTask, download success, task:$task"
                )
            }

            override fun onError(task: Task, error: IError) {
                super.onError(task, error)
                failed?.invoke(error)
                Log.e(
                    TAG,
                    "addDownloadTask, task:$task, error:$error"
                )
            }
        })
        addDownloadTask(task)
        //App.instance.downloadService.addTask(task)
    }

    abstract fun addDownloadTask(task: Task)

    companion object {
        private const val TAG = "EffectViewModel"

        private suspend fun getSaveDir(): String {
            val dir = "${videoPath}${File.separator}"
            withContext(Dispatcher.WENEXT_THREAD_POOL) {
                createOrExistsDir(dir)
            }
            return dir
        }

        suspend fun getSavePath(url: String): String {
            return "${getSaveDir()}${"${url.md5()}.${url.split(".").last()}"}"
        }
    }

}