package com.stand.standapp.utils

import android.content.Context
import com.stand.standapp.AppConfig
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.asRequestBody
import timber.log.Timber
import java.io.*
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.Executors
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import kotlin.system.exitProcess

object LogManager {
    private val executor = Executors.newSingleThreadExecutor()
    private const val MAX_DAYS = 15
    private val client = OkHttpClient()
    private var logDir: File? = null

    fun init(context: Context) {
        Timber.plant(Timber.DebugTree())
        
        try {
            // 1. 路径确定
            val baseDir = context.getExternalFilesDir(null)
            logDir = if (baseDir != null) {
                File(baseDir, "logs")
            } else {
                File(context.filesDir, "logs")
            }

            if (logDir?.exists() == false) {
                val created = logDir?.mkdirs()
                android.util.Log.i("LogManager", "Directory created: $created at ${logDir?.absolutePath}")
            }
            
            // 2. 强行创建一个“自检”日志文件，不使用异步线程池
            logDir?.let { dir ->
                val testFile = File(dir, "startup_check.txt")
                try {
                    val fos = FileOutputStream(testFile, true)
                    fos.write("Logging started at ${Date()}\n".toByteArray())
                    fos.close()
                    android.util.Log.i("LogManager", "Startup check file written successfully")
                } catch (e: Exception) {
                    android.util.Log.e("LogManager", "FAILED to write startup check file", e)
                }
            }

            logDir?.let { 
                cleanOldLogs(it)
                Timber.plant(FileLoggingTree(it))
            }
            
            setupCrashHandler()
        } catch (e: Exception) {
            android.util.Log.e("LogManager", "Init global failure", e)
        }
    }

    /**
     * 专门供外部（如 xCrash 或其它处理器）调用的保存方法
     */
    fun onCrashDetected(logPath: String?, threadName: String?, throwable: Throwable?) {
        val timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()).format(Date())
        val crashInfo = StringBuilder().apply {
            append("\n\n=== [DETECTION] CRASH LOG ===\n")
            append("Time: $timestamp\n")
            append("Thread: ${threadName ?: "Unknown"}\n")
            logPath?.let { append("XCrash Report: $it\n") }
            throwable?.let {
                append("Exception: ${it.javaClass.simpleName}\n")
                append("Message: ${it.message}\n")
                append("Stacktrace:\n${it.stackTraceToString()}\n")
            }
            append("=== END OF DETECTION ===\n\n")
        }.toString()

        logDir?.let { dir ->
            try {
                val logFile = File(dir, SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date()) + ".log")
                FileOutputStream(logFile, true).use { 
                    it.write(crashInfo.toByteArray())
                    it.flush()
                    it.fd.sync()
                }
            } catch (e: Exception) {}
        }
    }

    private fun setupCrashHandler() {
        // 1. 捕获所有线程
        val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
        Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
            onCrashDetected(null, thread.name, throwable)
            defaultHandler?.uncaughtException(thread, throwable) ?: exitProcess(1)
        }

        // 2. 捕获主线程 Looper
        android.os.Handler(android.os.Looper.getMainLooper()).post {
            while (true) {
                try {
                    android.os.Looper.loop()
                } catch (e: Throwable) {
                    onCrashDetected(null, "MainLooper", e)
                    // 如果是 UnsatisfiedLinkError，这种错误无法恢复，必须抛出让系统处理
                    throw e 
                }
            }
        }
    }

    private fun cleanOldLogs(dir: File) {
        executor.execute {
            try {
                val thresholdDate = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -MAX_DAYS) }.time
                dir.listFiles()?.forEach { file ->
                    if (file.isFile && file.name.endsWith(".log") && Date(file.lastModified()).before(thresholdDate)) {
                        file.delete()
                    }
                }
            } catch (e: Exception) {}
        }
    }

    fun zipLogs(context: Context): String? {
        val zipFile = File(context.getExternalFilesDir(null), "full_logs_${System.currentTimeMillis()}.zip")
        val logFolder = logDir // 这通常是 files/logs
        val tombstoneFolder = File(context.getExternalFilesDir(null), "tombstones")

        return try {
            ZipOutputStream(FileOutputStream(zipFile)).use { zos ->
                // 1. 打包 logs 文件夹
                logFolder?.let { addFolderToZip(zos, it, "logs") }
                
                // 2. 打包 tombstones 文件夹
                if (tombstoneFolder.exists()) {
                    addFolderToZip(zos, tombstoneFolder, "tombstones")
                }
            }
            zipFile.absolutePath
        } catch (e: Exception) {
            android.util.Log.e("LogManager", "Zip failed", e)
            null
        }
    }

    private fun addFolderToZip(zos: ZipOutputStream, folder: File, parentName: String) {
        folder.listFiles()?.forEach { file ->
            if (file.isFile) {
                try {
                    val entry = ZipEntry("$parentName/${file.name}")
                    zos.putNextEntry(entry)
                    FileInputStream(file).use { it.copyTo(zos) }
                    zos.closeEntry()
                } catch (e: Exception) {}
            }
        }
    }

    fun shutdown() {
        Timber.tag("LogManager").i("Shutting down...")
        try {
            executor.shutdown()
            executor.awaitTermination(3, java.util.concurrent.TimeUnit.SECONDS)
        } catch (e: Exception) {
            Timber.tag("LogManager").e(e, "Executor shutdown failed")
        }
    }

    fun uploadLogs(context: Context, callback: (Boolean, String) -> Unit) {
        executor.execute {
            val zipPath = zipLogs(context) ?: return@execute callback(false, "打包失败")
            val serverUrl = AppConfig.getServerUrl(context)
            val uploadUrl = "$serverUrl/api/attachment/upload"
            val bearerToken = "eyJraWQiOiJzLXYxIiwidHlwIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.eyJzdWIiOiJhZG1pbiIsInR5cCI6ImFjY2VzcyIsImV4cCI6MTc3NjQ5MDczNSwianRpIjoiMjYzNjljYzQtYzJiMy00YTg0LWFiYTMtZDU4NmNiZDRmMmM0IiwiZmdwIjoiY2FhNzYzOTI4YWRhYWZiYjgzMjE3NjExYmVjYTc3ZjMiLCJraWQiOiJzLXYxIn0.AyuzNAe-R_GOBC65STH5qpHkmmUngX8rMBPI4CdIIhk"

            val body = MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("file", File(zipPath).name, File(zipPath).asRequestBody("application/zip".toMediaTypeOrNull()))
                .build()

            val request = Request.Builder().url(uploadUrl).header("Authorization", "Bearer $bearerToken").post(body).build()
            try {
                client.newCall(request).execute().use { response ->
                    if (response.isSuccessful) {
                        callback(true, "上传成功")
                        File(zipPath).delete()
                    } else callback(false, "错误: ${response.code}")
                }
            } catch (e: IOException) { callback(false, "失败: ${e.message}") }
        }
    }

    private class FileLoggingTree(private val logDir: File) : Timber.Tree() {
        private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
        private val fileNameFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())

        override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
            executor.execute {
                try {
                    val logFile = File(logDir, "${fileNameFormat.format(Date())}.log")
                    val priorityStr = when (priority) { 2->"V" 3->"D" 4->"I" 5->"W" 6->"E" 7->"A" else->"U" }
                    val entry = "${dateFormat.format(Date())} $priorityStr/[$tag]: $message\n${t?.stackTraceToString() ?: ""}\n"
                    FileWriter(logFile, true).use { it.write(entry) }
                } catch (e: Exception) {}
            }
        }
    }
}
