package com.example.myapplication.utils

import android.content.Context
import android.util.Log
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipInputStream

private const val TAG_UNZIP = "1314520-unzip"
private const val TAG_ZIPLIST = "1314520-ziplist"

/* =========================
 *  1️⃣ 打印 zip 内容（调试用）
 * ========================= */
fun logZipEntries(zipFile: File) {
    Log.e(TAG_ZIPLIST, "========== ZIP CONTENT START ==========")
    Log.e(TAG_ZIPLIST, "zipPath=${zipFile.absolutePath} size=${zipFile.length()}")

    try {
        FileInputStream(zipFile).use { fis ->
            ZipInputStream(BufferedInputStream(fis)).use { zis ->
                var count = 0
                while (true) {
                    val entry = zis.nextEntry ?: break
                    count++
                    Log.e(
                        TAG_ZIPLIST,
                        "[$count] ${entry.name}  dir=${entry.isDirectory}"
                    )
                    zis.closeEntry()
                }
                Log.e(TAG_ZIPLIST, "total entries=$count")
            }
        }
    } catch (e: Exception) {
        Log.e(TAG_ZIPLIST, "read zip failed: ${e.message}", e)
    }

    Log.e(TAG_ZIPLIST, "========== ZIP CONTENT END ==========")
}

fun detectArchiveType(file: File): String {
    FileInputStream(file).use { fis ->
        val header = ByteArray(8)
        val read = fis.read(header)
        if (read < 4) return "UNKNOWN"

        fun hex(vararg b: Int) =
            b.map { it.toByte() }.toByteArray().contentEquals(header.copyOf(b.size))

        return when {
            hex(0x50, 0x4B, 0x03, 0x04) -> "ZIP"
            hex(0x50, 0x4B, 0x05, 0x06) -> "ZIP_EMPTY"
            hex(0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C) -> "7Z"
            hex(0x52, 0x61, 0x72, 0x21) -> "RAR"
            else -> "UNKNOWN"
        }
    }
}

fun validateZipWithZipFile(zip: File) {
    try {
        ZipFile(zip).use { zf ->
            val e = zf.entries()
            var count = 0
            while (e.hasMoreElements()) {
                val entry = e.nextElement()
                Log.e("1314520-zipfile", "entry=${entry.name}")
                count++
            }
            Log.e("1314520-zipfile", "ZipFile entries=$count")
        }
    } catch (e: Exception) {
        Log.e("1314520-zipfile", "ZipFile FAILED: ${e.message}", e)
    }
}

/* =========================
 *  2️⃣ 是否是垃圾文件
 * ========================= */
private fun isJunkEntry(name: String): Boolean {
    if (name.startsWith("__MACOSX/")) return true
    val last = name.substringAfterLast('/')
    if (last.startsWith("._")) return true
    if (last == ".DS_Store") return true
    return false
}

/* =========================
 *  3️⃣ 是否是「zip 里套 zip」
 * ========================= */
private fun findSingleInnerZip(zipFile: File): String? {
    ZipFile(zipFile).use { zip ->
        val entries = zip.entries().toList()
        if (entries.size == 1) {
            val e = entries.first()
            if (!e.isDirectory && e.name.endsWith(".zip", ignoreCase = true)) {
                return e.name
            }
        }
    }
    return null
}

/* =========================
 *  4️⃣ 解出内层 zip
 * ========================= */
private fun extractInnerZip(
    zipFile: File,
    entryName: String,
    outFile: File
) {
    ZipFile(zipFile).use { zip ->
        val entry = zip.getEntry(entryName)
            ?: error("Inner zip not found: $entryName")

        zip.getInputStream(entry).use { input ->
            FileOutputStream(outFile).use { output ->
                input.copyTo(output)
            }
        }
    }
}

/* =========================
 *  5️⃣ 智能入口（唯一对外）
 * ========================= */
fun unzipThemeSmart(
    context: Context,
    zipFile: File,
    themeId: Int,
    targetBaseDir: File = File(context.filesDir, "keyboard_themes")
): String {
    // 👉 检测嵌套 zip
    val innerZipName = findSingleInnerZip(zipFile)
    if (innerZipName != null) {

        val tempInnerZip = File(
            context.cacheDir,
            "inner_${System.currentTimeMillis()}.zip"
        )

        extractInnerZip(zipFile, innerZipName, tempInnerZip)

        val result = unzipThemeSmart(
            context = context,
            zipFile = tempInnerZip,
            themeId = themeId,
            targetBaseDir = targetBaseDir
        )

        tempInnerZip.delete()
        return result
    }

    // 👉 普通主题 zip
    return unzipThemeFromFileOverwrite_ZIS(
        context = context,
        zipFile = zipFile,
        themeId = themeId,
        targetBaseDir = targetBaseDir
    )
}

/* =========================
 *  6️⃣ 真正的主题解压（你原逻辑）
 * ========================= */
fun unzipThemeFromFileOverwrite_ZIS(
    context: Context,
    zipFile: File,
    themeId: Int,
    targetBaseDir: File
): String {

    val tempOut = File(context.cacheDir, "tmp_theme_out").apply {
        if (exists()) deleteRecursively()
        mkdirs()
    }
    val canonicalTempOut = tempOut.canonicalFile.path + File.separator

    fun findIconsRelativePath(entryName: String): String? {
        val n = entryName.replace('\\', '/')
        val lower = n.lowercase()

        val idxIcons = lower.indexOf("/icons/")
        val idxIcon = lower.indexOf("/icon/")

        val idx = when {
            idxIcons >= 0 -> idxIcons + 7
            idxIcon >= 0 -> idxIcon + 6
            lower.startsWith("icons/") -> 6
            lower.startsWith("icon/") -> 5
            else -> return null
        }
        return n.substring(idx)
    }

    fun isBackground(entryName: String): Boolean =
        entryName.substringAfterLast('/')
            .equals("background.png", ignoreCase = true)

    var sawAnyEntry = false
    var extractedAnyIcons = false

    try {
        ZipInputStream(BufferedInputStream(FileInputStream(zipFile))).use { zis ->
            val buffer = ByteArray(8192)

            while (true) {
                val entry: ZipEntry = zis.nextEntry ?: break
                sawAnyEntry = true
                val name = entry.name

                if (isJunkEntry(name)) {
                    zis.closeEntry(); continue
                }

                val iconsRel = findIconsRelativePath(name)
                val isIcons = iconsRel != null
                val isBg = isBackground(name)

                if (!isIcons && !isBg) {
                    zis.closeEntry(); continue
                }

                val relativeOut = if (isIcons) iconsRel!! else "background.png"
                val outFile = File(tempOut, relativeOut)

                val canonicalOut = outFile.canonicalFile.path
                if (!canonicalOut.startsWith(canonicalTempOut)) {
                    zis.closeEntry(); continue
                }

                if (!entry.isDirectory) {
                    outFile.parentFile?.mkdirs()
                    FileOutputStream(outFile).use { fos ->
                        while (true) {
                            val c = zis.read(buffer)
                            if (c == -1) break
                            fos.write(buffer, 0, c)
                        }
                    }
                    if (isIcons) extractedAnyIcons = true
                }
                zis.closeEntry()
            }
        }

        if (!sawAnyEntry)
            throw IllegalStateException("zip 为空或损坏")
        if (!extractedAnyIcons)
            throw IllegalStateException("未找到 icons/icon 文件（请看 ziplist 日志）")

        val finalDir = File(targetBaseDir, themeId.toString())
        if (finalDir.exists()) finalDir.deleteRecursively()
        finalDir.parentFile?.mkdirs()

        if (!tempOut.renameTo(finalDir)) {
            finalDir.mkdirs()
            tempOut.copyRecursively(finalDir, overwrite = true)
            tempOut.deleteRecursively()
        }
        return themeId.toString()

    } catch (e: Exception) {
        logZipEntries(zipFile)
        Log.e(TAG_UNZIP, "解压失败: ${e.message}", e)
        throw e
    } finally {
        if (tempOut.exists()) tempOut.deleteRecursively()
    }
}
