package com.gh.vspace

import android.content.Context
import android.os.Build
import android.os.Environment
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.vspace.db.VGameDatabase
import com.lightgame.utils.Utils
import net.lingala.zip4j.ZipFile
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.channels.FileChannel
import java.nio.file.Files

object VBackupHelper {

    // 添加数据库版本作为路径，避免数据错乱异常
    private const val BACKUP_FOLDER = "/gh-files/vspace_backup/" + VGameDatabase.DB_VERSION

    fun recoverValidData(context: Context) {
        runOnIoThread {
            recoverFromBackupDb(context)
        }
    }

    private fun recoverFromBackupDb(context: Context) {
        try {
            val backupDir = File(Environment.getExternalStorageDirectory().absolutePath + BACKUP_FOLDER)
            val backupSubDir = File(Environment.getExternalStorageDirectory().absolutePath + BACKUP_FOLDER + "/files")
            val databaseDir: File? = context.getDatabasePath(VGameDatabase.DATABASE).parentFile

            if (backupDir.canWrite() && databaseDir != null) {
                backupDir.listFiles()?.forEach {
                    if (it.name.endsWith(".zip")) {
                        if (MD5Utils.calculateMD5(it) == it.nameWithoutExtension) {
                            val zipFile = ZipFile(it)
                            zipFile.extractAll(backupDir.absolutePath)
                        } else {
                            Utils.log("备份的压缩包 MD5 变了，可能损坏，中止还原")
                            return
                        }
                    }
                    it.delete()
                }

                backupSubDir.listFiles()?.forEach {
                    if (it.name.endsWith(".bak")) {
                        val src: FileChannel = FileInputStream(it).channel
                        val dst: FileChannel =
                            FileOutputStream(File(databaseDir.absolutePath + "/${it.name.removeSuffix(".bak")}")).channel
                        dst.transferFrom(src, 0, src.size())
                        src.close()
                        dst.close()

                        it.delete()

                        Utils.log("Recover ${it.name} successful!")
                    }
                }

                backupDir.deleteRecursively()
            }

            VArchiveHelper.clearAllArchives()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 备份现有数据库到 SD 卡
     */
    fun backupDBToExternalStorage(context: Context) {
        val backupDir = File(Environment.getExternalStorageDirectory().absolutePath + BACKUP_FOLDER)
        val backupSubDir = File(Environment.getExternalStorageDirectory().absolutePath + BACKUP_FOLDER + "/files")
        val databaseDir: File? = context.getDatabasePath(VGameDatabase.DATABASE).parentFile

        backupDir.deleteRecursively()

        if (backupDir.parentFile?.exists() == false) {
            backupDir.parentFile?.mkdir()
        }

        backupDir.mkdir()
        backupSubDir.mkdir()

        try {
            if (backupSubDir.canWrite() && databaseDir != null) {
                databaseDir.listFiles()?.forEach {
                    if (it.name.contains(VGameDatabase.DATABASE)) {
                        val src: FileChannel = FileInputStream(it).channel
                        val dst: FileChannel =
                            FileOutputStream(File(backupSubDir.absolutePath + "/${it.name}" + ".bak")).channel
                        dst.transferFrom(src, 0, src.size())
                        src.close()
                        dst.close()

                        Utils.log("Backup ${it.name} successful!")
                    }
                }
            }

            val backupZip =
                ZipFile(backupDir.absolutePath + "/" + backupSubDir.name + ".zip").apply { addFolder(backupSubDir) }

            backupSubDir.deleteRecursively()

            val fileName = MD5Utils.calculateMD5(backupZip.file)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Files.move(backupZip.file.toPath(), File(backupDir.absolutePath + "/" + fileName + ".zip").toPath())
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun removeAllDatabase(context: Context) {
        try {
            val rootDir: File = Environment.getExternalStorageDirectory()
            if (rootDir.canWrite()) {
                val backupDBPath = String.format("/gh-files/%s.bak", VGameDatabase.DATABASE)
                val externalDB = File(rootDir, backupDBPath)

                externalDB.delete()
                context.deleteDatabase(VGameDatabase.DATABASE)

                Utils.log("Import Download DB Successful!")
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

}