package com.develop.food.base.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.food.base.FoodCookBaseApp
import com.develop.food.base.common.CURRENT_USER_ID_TAG
import com.develop.food.base.repo.db.FoodDatabase
import com.develop.food.base.repo.db.UserDatabase
import com.develop.food.base.utils.FileKit
import com.develop.food.base.utils.GlobalApp
import com.develop.food.base.utils.MmkvUtils
import com.develop.food.base.utils.ThreadUtils
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 val RES_DST_PATH = File(RES_DST_PARENT, "cofa_cooking")
    private val preparedLock = CountDownLatch(1)
    private var foodDatabase: FoodDatabase? = null
    private var userDatabase: UserDatabase? = null
    private val prepareLiveData = MutableLiveData<Boolean>()

    fun prepareData(application: Application) {
        ThreadUtils.runOnWorkThread(Runnable {
            if (RES_DST_PATH.exists()) {
                validateDatabaseFile()
                preparedLock.countDown()
                return@Runnable
            }
            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()
                ToastUtils.showShort("数据包解压失败! 请检查数据包")
            }
            Log.d("FoodDataProvider", "数据解压成功!")
            preparedLock.countDown()
        })
    }

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

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

    fun getResourcePath(relativePath: String?): String {
        if (relativePath?.startsWith("http") == true) {
            return relativePath
        }
        preparedLock.await()
        return "${RES_DST_PARENT}/$relativePath"
    }

    fun getResourceDir(): File {
        return RES_DST_PATH
    }

    fun getExtRecipeResourceDir(): File {
        return RES_DST_PARENT
    }

    fun isResourceDownload(recipeNum: String): Boolean {
        return getResourceConfigJsonPath(recipeNum).exists()
    }

    fun getResourceConfigJsonPath(recipeNum: String): File {
        val relPath = "_data/recipe/${recipeNum}/data.json"
        return File(RES_DST_PATH, relPath)
    }

    /**
     * 作兼容处理, 资源包里的图片格式可能是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")}"
        }
    }

    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()
            }
        }
    }

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

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

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

val CURRENT_USER_ID = MmkvUtils.getLong(CURRENT_USER_ID_TAG) ?: 10001L