package com.develop.common.data_repo

import android.app.Application
import android.os.Environment
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.room.Room
import com.blankj.utilcode.util.FileUtils
import com.blankj.utilcode.util.ToastUtils
import com.blankj.utilcode.util.ZipUtils
import com.develop.base.BuildConfig
import com.develop.base.app.BaseApp
import com.develop.base.ext.globalApp
import com.develop.base.util.FileKit
import com.develop.base.util.GlobalToast
import com.develop.base.util.ThreadUtils
import com.develop.common.data_repo.db.FoodDatabase
import com.develop.common.data_repo.db.MIGRATION_1_2
import com.develop.common.data_repo.db.UserDatabase
import com.drake.net.utils.scope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.util.concurrent.CountDownLatch

/**
 * 全局管理数据
 */
object FoodDataProvider {
    private val SYSTEM_MODE = BuildConfig.DEBUG
    private val RES_DST_PARENT = if (SYSTEM_MODE) {
        Environment.getExternalStorageDirectory()
    } else {
        globalApp().externalCacheDir!!
    }
    private var foodDatabase: FoodDatabase? = null
    private var userDatabase: UserDatabase? = null
    private var prepareLiveData = MutableLiveData<Boolean>()
    private val preparedLock = CountDownLatch(1)
    private val RES_DST_PATH = File(RES_DST_PARENT, "cofa_cooking")

    /**预先准备好菜品资源包数据*/
    fun prepareData(application: Application) {
        var isSuccess = true
        ThreadUtils.runOnWorkThread({
            if (RES_DST_PATH.exists()) {
                validateDatabaseFile()
                preparedLock.countDown()
            } else {
                val allFiles = RES_DST_PARENT.listFiles() ?: emptyArray()
                var targetZipFile: File? = null
                for (file in allFiles) {
                    if (file.isDirectory) {
                        continue
                    }
                    if (file.name.endsWith("cofa_cooking.zip")) {
                        targetZipFile = file
                        break
                    }
                }
                if (targetZipFile == null) {
                    FileKit.copyAssetsFile(
                        application,
                        "cofa_cooking.zip",
                        File(RES_DST_PARENT, "cofa_cooking.zip").absolutePath
                    )
                    targetZipFile = File(RES_DST_PARENT, "cofa_cooking.zip")
                }
                try {
                    val start = System.currentTimeMillis()
                    ZipUtils.unzipFile(targetZipFile, RES_DST_PARENT)
                    Log.d(
                        "FoodDataProvider", "cost time:${System.currentTimeMillis() - start}"
                    )
                    validateDatabaseFile()
                } catch (ex: Exception) {
                    ex.printStackTrace()
                    Log.d("FoodDataProvider", "${ex.message.toString()}")
                    isSuccess = false
                }
                if (isSuccess) {
                    prepareLiveData.postValue(true)
                    Log.d("FoodDataProvider", "数据解压成功!")
                } else {
                    GlobalToast.showToast("数据包解压失败! 请检查数据包")
                    prepareLiveData.postValue(false)
                }
                preparedLock.countDown()
            }
        })
    }

    /**作兼容处理, 资源包里的图片格式可能是jpg或png*/
    fun getImagePath(relativePath: String?): String {
        if (relativePath?.startsWith("http") == true) {
            return relativePath
        }
        preparedLock.await()
        if (relativePath == null) {
            return ""
        }
        val resFile = getResource(relativePath)
        if (resFile.exists()) {
            return resFile.absolutePath
        }
        return if (relativePath.endsWith("png")) {
            "$RES_DST_PATH/${relativePath.replace("png", "jpg")}"
        } else {
            "$RES_DST_PATH/${relativePath.replace("jpg", "png")}"
        }
    }

    /**根据菜品number删除对应资源文件*/
    fun deleteRecipeResource(recipeNum: String) {
        val relPath = "_data/recipe/${recipeNum}"
        val dir = File(RES_DST_PATH, relPath)
        if (dir.exists()) {
            try {
                FileUtils.delete(dir)
            } catch (ex: Exception) {
                ex.printStackTrace()
            }
        }
    }

    /**删除菜品资源包*/
    fun deleteAll() {
        if (RES_DST_PATH.exists()) {
            try {
                FileUtils.delete(RES_DST_PATH)
            } catch (ex: Exception) {
                ex.printStackTrace()
            }
        }
    }

    /**根据菜品number获取configJson文件*/
    fun getResourceConfigJsonPath(recipeNum: String): File {
        val relPath = "_data/recipe/${recipeNum}/data.json"
        return File(RES_DST_PATH, relPath)
    }

    /**判断菜品number对应的configJson文件是否存在*/
    fun isResourceDownload(recipeNum: String): Boolean {
        return getResourceConfigJsonPath(recipeNum).exists()
    }

    /**获取菜品资源包文件*/
    fun getExtRecipeResourceDir(): File {
        return RES_DST_PARENT
    }

    /**获取菜品图片路径*/
    fun getResourcePath(relativePath: String?): String {
        if(relativePath == null){
            return  ""
        }
        if (relativePath?.startsWith("http") == true) {
            return relativePath
        }
        preparedLock.await()
        return "$RES_DST_PARENT/$relativePath"
    }

    private fun getResource(relativePath: String): File {
        preparedLock.await()
        return File(RES_DST_PATH, relativePath)
    }

    private fun validateDatabaseFile() {
        val dbFile = RES_DST_PATH.listFiles { it ->
            it.name.endsWith(".db")
        }
        if (dbFile.isNullOrEmpty()) {
            ToastUtils.showShort("数据包文件结构有误, 请检查数据包")
            prepareLiveData.postValue(false)
        } else {
            Log.d("FoodDataProvider", "数据包校验成功")
            prepareLiveData.postValue(true)
        }

    }

    fun getPrepareLiveData(): LiveData<Boolean> {
        return prepareLiveData
    }

    @Synchronized
    fun getDatabase(): FoodDatabase {
        if (foodDatabase != null) {
            return foodDatabase!!
        }
        preparedLock.await()
        val dbFile = File(RES_DST_PATH, "sqlite.db")
        foodDatabase = Room.databaseBuilder(
            BaseApp.application, FoodDatabase::class.java, "sqlite.db"
        ).allowMainThreadQueries().createFromFile(dbFile).build()
        return foodDatabase!!
    }

    @Synchronized
    fun getUserDatabase(): UserDatabase {
        if (userDatabase != null) {
            return userDatabase!!
        }
        userDatabase = Room.databaseBuilder(
            BaseApp.application, UserDatabase::class.java, "userInfo"
        ).allowMainThreadQueries().addMigrations(MIGRATION_1_2).build()
        return userDatabase!!
    }

    fun checkDataExit(): Boolean {
        val result = prepareLiveData.value == true
        if (!result) {
            prepareData(globalApp())
        }
        return prepareLiveData.value == true
    }
}