package com.example.myapplication.theme

import android.content.Context
import android.content.res.AssetManager
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import java.io.File
object ThemeManager {

    // SharedPreferences 保存当前主题名
    private const val PREF_NAME = "ime_theme_prefs"
    private const val KEY_CURRENT_THEME = "current_theme"

    // 当前主题名（如 "default"）
    @Volatile
    private var currentThemeName: String? = null

    // 缓存：规范化后的 keyName(lowercase) -> Drawable
    @Volatile
    private var drawableCache: MutableMap<String, Drawable> = mutableMapOf()

    // ==================== 外部目录相关 ====================
    //通知主题更新
    private val listeners = mutableSetOf<() -> Unit>()

    fun addThemeChangeListener(listener: () -> Unit) {
        listeners.add(listener)
    }

    fun removeThemeChangeListener(listener: () -> Unit) {
        listeners.remove(listener)
    }


    /** 主题根目录：/Android/data/<package>/files/keyboard_themes */
    private fun getThemeRootDir(context: Context): File =
        File(context.filesDir, "keyboard_themes")

    /** 某个具体主题目录：/Android/.../keyboard_themes/<themeName> */
    private fun getThemeDir(context: Context, themeName: String): File =
        File(getThemeRootDir(context), themeName)

    fun ensureBuiltInThemesInstalled(context: Context) {
        val am = context.assets
        val rootName = "keyboard_themes"
        val themeRootDir = getThemeRootDir(context)
        if (!themeRootDir.exists()) themeRootDir.mkdirs()

        // 列出 assets/keyboard_themes 下的所有子目录，比如 default、dark...
        val themeNames = am.list(rootName) ?: return

        for (themeName in themeNames) {
            val assetThemePath = "$rootName/$themeName"   // 如 keyboard_themes/default
            val targetThemeDir = getThemeDir(context, themeName)
            copyAssetsDirToDir(am, assetThemePath, targetThemeDir)
        }
    }

    /**
     * 递归地将 assets 中的某个目录合并复制到目标 File 目录下。
     *
     * 规则：
     * - 如果目标目录不存在，则创建。
     * - 如果目标文件已存在，则跳过（不覆盖用户改过的图）。
     * - 如果是新文件，则复制过去（补充新图）。
     */
    private fun copyAssetsDirToDir(
        assetManager: AssetManager,
        assetDir: String,
        targetDir: File
    ) {
        if (!targetDir.exists()) targetDir.mkdirs()

        val children = assetManager.list(assetDir) ?: return
        for (child in children) {
            val childAssetPath = "$assetDir/$child"
            val outFile = File(targetDir, child)

            val grandChildren = assetManager.list(childAssetPath)
            if (grandChildren?.isNotEmpty() == true) {
                // 子目录，递归
                copyAssetsDirToDir(assetManager, childAssetPath, outFile)
            } else {
                // 文件：如果已经存在就不覆盖；不存在才复制（补充新图）
                if (outFile.exists()) continue

                assetManager.open(childAssetPath).use { input ->
                    outFile.outputStream().use { output ->
                        input.copyTo(output)
                    }
                }
            }
        }
    }

    // ==================== 主题初始化 / 切换 ====================

    /**
     * 初始化主题系统：
     * - 读取 SharedPreferences 中上次使用的主题名
     * - 默认使用 "default"
     * - 加载该主题的所有图片到缓存
     */
    fun init(context: Context) {
        if (currentThemeName != null) return

        val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
        val name = prefs.getString(KEY_CURRENT_THEME, "default") ?: "default"
        setCurrentTheme(context, name)
    }

    /**
     * 切换当前主题：
     * - 更新 currentThemeName
     * - 写 SharedPreferences
     * - 重新加载该主题的全部图片到缓存
     */
    fun setCurrentTheme(context: Context, themeName: String) {
        currentThemeName = themeName

        context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
            .edit()
            .putString(KEY_CURRENT_THEME, themeName)
            .apply()

        drawableCache = loadThemeDrawables(context, themeName)

        listeners.forEach { it.invoke() }
    }

    fun getCurrentThemeName(): String? = currentThemeName

    /**
     * 扫描某个主题目录下的所有 png/jpg/webp 文件，
     * 用“文件名（去掉扩展名，小写）”作为 keyName，构造缓存。
     *
     * 例如：
     *   /.../keyboard_themes/default/key_a.png      -> "key_a"
     *   /.../keyboard_themes/default/key_a_up.PNG  -> "key_a_up"
     */
    private fun loadThemeDrawables(
        context: Context,
        themeName: String
    ): MutableMap<String, Drawable> {
        val map = mutableMapOf<String, Drawable>()
        val dir = getThemeDir(context, themeName)

        if (!dir.exists() || !dir.isDirectory) return map

        dir.listFiles()?.forEach { file ->
            if (!file.isFile) return@forEach

            val lowerName = file.name.lowercase()
            if (
                !(lowerName.endsWith(".png") ||
                  lowerName.endsWith(".jpg") ||
                  lowerName.endsWith(".jpeg") ||
                  lowerName.endsWith(".webp"))
            ) return@forEach

            // 统一小写作为 key，比如 key_a_up.png -> "key_a_up"
            val key = lowerName.substringBeforeLast(".")
            val bmp = BitmapFactory.decodeFile(file.absolutePath) ?: return@forEach
            val d = BitmapDrawable(context.resources, bmp)
            map[key] = d
        }

        return map
    }

    // ==================== 对外：按 keyName 取 Drawable ====================

    /**
     * 根据 keyName 获取对应的 Drawable。
     *
     * keyName 一般就是 view 的 idName：
     * - "key_a"
     * - "key_a_up"
     * - "key_1"
     * - "key_space"
     * - "key_send"
     * ...
     *
     * 对应文件：
     *   /Android/data/.../files/keyboard_themes/<当前主题>/key_a.png
     *
     * 内部统一用 keyName.lowercase() 做匹配，不区分大小写。
     */
    fun getDrawableForKey(context: Context, keyName: String): Drawable? {
        if (currentThemeName == null) {
            init(context)
        }

        // 统一小写，避免大小写差异
        val norm = keyName.lowercase()

        // 1) 缓存里有就直接返回
        drawableCache[norm]?.let { return it }

        // 2) 缓存里没有：尝试从当前主题目录里单独加载一遍（兼容运行时新增图片）
        val theme = currentThemeName ?: return null
        val dir = getThemeDir(context, theme)

        val candidates = listOf(
            File(dir, "$norm.png"),
            File(dir, "$norm.webp"),
            File(dir, "$norm.jpg"),
            File(dir, "$norm.jpeg")
        )

        for (f in candidates) {
            if (f.exists() && f.isFile) {
                val bmp = BitmapFactory.decodeFile(f.absolutePath) ?: continue
                val d = BitmapDrawable(context.resources, bmp)
                drawableCache[norm] = d
                return d
            }
        }

        // 3) 找不到就返回 null（调用方自己决定是否兜底）
        return null
    }

    // ==================== 可选：列出所有已安装主题 ====================

    /**
     * 返回当前外部目录下所有已经存在的主题名列表，
     * 例如 ["default", "dark", "cute_pink"]。
     */
    fun listAvailableThemes(context: Context): List<String> {
        val root = getThemeRootDir(context)
        if (!root.exists() || !root.isDirectory) return emptyList()

        return root.listFiles()
            ?.filter { it.isDirectory }
            ?.map { it.name }
            ?.sorted()
            ?: emptyList()
    }
}
