package com.example.firefly_go_android

import android.app.Activity
import android.content.Context
import android.util.Log
import libandroid.Libandroid
import java.io.File
import java.io.FileOutputStream
import java.util.zip.ZipFile

object FireflyModMenu {

    @Volatile
    private var isServerStarted = false

    @JvmStatic
    fun init(activity: Activity) {
        val modPackageName = "com.kain344.firefly_go_android"
        Log.d("FireflyMod", "Initializing FireflyModMenu for module: $modPackageName")

        val appDataPath = File(activity.getExternalFilesDir(null), "FireflyGo").absolutePath
        val dataDir = File("$appDataPath/data")
        if (!dataDir.exists()) dataDir.mkdirs()

        val sharedPrefs = activity.getSharedPreferences("FireflyModPrefs", Context.MODE_PRIVATE)
        
        val apkPath = getModuleApkPath(FireflyModMenu::class.java.classLoader)
        
        val currentUpdateTime = if (apkPath != null) {
            try {
                val lastModified = File(apkPath).lastModified()
                Log.d("FireflyMod", "Module APK path: $apkPath, Last modified: $lastModified")
                lastModified
            } catch (e: Exception) {
                Log.e("FireflyMod", "Lỗi khi lấy last modified của APK: ${e.message}")
                0L
            }
        } else {
            // Fallback to PackageManager if APK path could not be resolved
            try {
                val packageInfo = activity.packageManager.getPackageInfo(modPackageName, 0)
                Log.d("FireflyMod", "Module package found. Last update: ${packageInfo.lastUpdateTime}")
                packageInfo.lastUpdateTime
            } catch (e: Exception) {
                Log.e("FireflyMod", "Module package $modPackageName not found: ${e.message}")
                0L
            }
        }
        
        val lastUpdateTime = sharedPrefs.getLong("last_update_time", 0L)
        val shouldOverride = currentUpdateTime != 0L && currentUpdateTime != lastUpdateTime
        if (shouldOverride) {
            Log.d("FireflyMod", "Module version changed (old: $lastUpdateTime, new: $currentUpdateTime). Forcing asset override.")
        }

        if (!isServerStarted) {
            Log.d("FireflyMod", "Starting Server thread...")
            isServerStarted = true
            Thread {
                try {
                    val isCopyDone = if (apkPath != null) {
                        copyRawFilesFromApk(apkPath, dataDir, shouldOverride)
                    } else {
                        // Fallback to createPackageContext
                        val modContext = try {
                            activity.createPackageContext(modPackageName, Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY)
                        } catch (e: Exception) {
                            Log.e("FireflyMod", "Không thể tạo mod context cho $modPackageName: ${e.message}")
                            null
                        }

                        if (modContext != null) {
                            copyRawFiles(modContext, dataDir, shouldOverride)
                        } else {
                            false
                        }
                    }

                    if (isCopyDone) {
                        if (shouldOverride) {
                            sharedPrefs.edit().putLong("last_update_time", currentUpdateTime).apply()
                        }
                        Libandroid.setPathDataLocal(appDataPath)
                        Libandroid.setServerRunning(true)
                        Log.d("FireflyMod", "Server started successfully.")
                    } else {
                        Log.e("FireflyMod", "Lỗi khi copy assets, server không được khởi chạy.")
                        isServerStarted = false
                    }
                } catch (e: Exception) {
                    Log.e("FireflyMod", "Error in server thread: ${e.message}", e)
                    isServerStarted = false
                }
            }.start()
        }
    }

    private fun getModuleApkPath(classLoader: ClassLoader?): String? {
        var cl = classLoader
        while (cl != null) {
            Log.d("FireflyMod", "Checking ClassLoader: ${cl.javaClass.name}")
            // 1. Try parsing toString() first (reflection-free, safe from hidden API checks)
            val pathFromToString = getModuleApkPathFromToString(cl)
            if (pathFromToString != null) {
                Log.d("FireflyMod", "Found APK path via ClassLoader toString(): $pathFromToString")
                return pathFromToString
            }

            // 2. Try reflection on this class loader
            val pathFromReflection = getModuleApkPathViaReflection(cl)
            if (pathFromReflection != null) {
                Log.d("FireflyMod", "Found APK path via reflection: $pathFromReflection")
                return pathFromReflection
            }

            cl = cl.parent
        }
        Log.w("FireflyMod", "Could not find module APK path in ClassLoader hierarchy.")
        return null
    }

    private fun getModuleApkPathFromToString(classLoader: ClassLoader): String? {
        val clString = classLoader.toString()
        val regexes = listOf(
            Regex("""zip file "([^"]+)""""),
            Regex("""zip file '([^']+)'"""),
            Regex("""\[([^\]]+\.(apk|zip))\]"""),
            Regex("""file:([^:\s]+\.(apk|zip))""")
        )
        
        var fallbackPath: String? = null
        for (regex in regexes) {
            val matches = regex.findAll(clString)
            for (match in matches) {
                if (match.groupValues.size > 1) {
                    val path = match.groupValues[1]
                    val file = File(path)
                    if (file.exists() && file.isFile) {
                        if (path.contains("com.kain344.firefly_go_android") && path.endsWith(".apk")) {
                            return path
                        }
                        if (path.endsWith(".apk") && fallbackPath == null) {
                            fallbackPath = path
                        }
                    }
                }
            }
        }
        
        // General path match for any absolute path ending with .apk or .zip
        val pathRegex = Regex("""(/[^:\s"']+\.(apk|zip))""")
        val pathMatches = pathRegex.findAll(clString)
        for (match in pathMatches) {
            val path = match.groupValues[1]
            val file = File(path)
            if (file.exists() && file.isFile) {
                if (path.contains("com.kain344.firefly_go_android") && path.endsWith(".apk")) {
                    return path
                }
                if (path.endsWith(".apk") && fallbackPath == null) {
                    fallbackPath = path
                }
            }
        }
        
        return fallbackPath
    }

    private fun getModuleApkPathViaReflection(classLoader: ClassLoader): String? {
        try {
            val baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader")
            if (!baseDexClassLoaderClass.isInstance(classLoader)) return null
            
            val pathListField = baseDexClassLoaderClass.getDeclaredField("pathList")
            pathListField.isAccessible = true
            val pathList = pathListField.get(classLoader) ?: return null

            val dexElementsField = pathList.javaClass.getDeclaredField("dexElements")
            dexElementsField.isAccessible = true
            val dexElements = dexElementsField.get(pathList) as? Array<*> ?: return null

            var fallbackApkPath: String? = null
            for (element in dexElements) {
                if (element == null) continue
                val elementClass = element.javaClass
                val fileField = try {
                    elementClass.getDeclaredField("file")
                } catch (e: NoSuchFieldException) {
                    try {
                        elementClass.getDeclaredField("path")
                    } catch (ex: NoSuchFieldException) {
                        null
                    }
                }
                if (fileField != null) {
                    fileField.isAccessible = true
                    val file = fileField.get(element) as? File
                    if (file != null && file.exists() && file.isFile) {
                        val path = file.absolutePath
                        if (path.contains("com.kain344.firefly_go_android") && path.endsWith(".apk")) {
                            return path
                        }
                        if (path.endsWith(".apk") && fallbackApkPath == null) {
                            fallbackApkPath = path
                        }
                    }
                }
            }
            return fallbackApkPath
        } catch (e: Exception) {
            Log.d("FireflyMod", "Reflection failed on ClassLoader ${classLoader.javaClass.name}: ${e.message}")
        }
        return null
    }

    private fun copyRawFilesFromApk(apkPath: String, targetDir: File, override: Boolean = false): Boolean {
        val files = listOf(
            "data-in-game.json" to "data-in-game.json",
            "freesr-data.json" to "freesr-data.json",
            "version.json" to "version.json"
        )
        
        return try {
            ZipFile(apkPath).use { zip ->
                for ((assetFile, outName) in files) {
                    val outFile = File(targetDir, outName)
                    if (outFile.exists() && !override) {
                        Log.d("FireflyMod", "Bỏ qua $outName (đã tồn tại)")
                        continue
                    }
                    
                    val entryName = "assets/$assetFile"
                    val entry = zip.getEntry(entryName)
                    if (entry == null) {
                        Log.e("FireflyMod", "Không tìm thấy entry $entryName trong APK")
                        return false
                    }
                    
                    zip.getInputStream(entry).use { input ->
                        FileOutputStream(outFile).use { output ->
                            input.copyTo(output)
                            output.fd.sync()
                        }
                    }
                    Log.d("FireflyMod", "Đã copy $assetFile từ APK thành công (override=$override)")
                }
            }
            true
        } catch (e: Exception) {
            Log.e("FireflyMod", "Lỗi khi copy file từ APK: ${e.message}", e)
            false
        }
    }

    private fun copyRawFiles(context: Context, targetDir: File, override: Boolean = false): Boolean {
        val files = listOf(
            "data-in-game.json" to "data-in-game.json",
            "freesr-data.json" to "freesr-data.json",
            "version.json" to "version.json"
        )
        
        return try {
            // Kiểm tra danh sách assets có sẵn để debug
            val availableAssets = context.assets.list("")?.toList() ?: emptyList()
            Log.d("FireflyMod", "Assets có sẵn trong module: $availableAssets")

            for ((assetFile, outName) in files) {
                val outFile = File(targetDir, outName)
                if (outFile.exists() && !override) {
                    Log.d("FireflyMod", "Bỏ qua $outName (đã tồn tại)")
                    continue
                }

                if (!availableAssets.contains(assetFile)) {
                    Log.w("FireflyMod", "Cảnh báo: Không tìm thấy $assetFile trong danh sách assets của module!")
                }

                context.assets.open(assetFile).use { input ->
                    FileOutputStream(outFile).use { output ->
                        input.copyTo(output)
                        output.fd.sync()
                    }
                }
                Log.d("FireflyMod", "Đã copy $assetFile thành công (override=$override)")
            }
            true
        } catch (e: Exception) {
            Log.e("FireflyMod", "Lỗi khi copy file từ assets của ${context.packageName}: ${e.message}", e)
            false
        }
    }
}
