package com.hikoncont.crash

import android.content.Context
import android.os.Build
import android.util.Log
import java.io.File
import java.io.PrintWriter
import java.io.StringWriter
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

/**
 * 全局未捕获异常处理器
 * 捕获崩溃信息写入本地文件，重启后由 CrashLogUploader 上传服务器
 */
class CrashHandler private constructor() : Thread.UncaughtExceptionHandler {

    companion object {
        private const val TAG = "CrashHandler"
        private const val CRASH_DIR = "crash_logs"
        private const val MAX_LOG_FILES = 20 // 最多保留20个崩溃日志

        @Volatile
        private var instance: CrashHandler? = null

        fun getInstance(): CrashHandler {
            return instance ?: synchronized(this) {
                instance ?: CrashHandler().also { instance = it }
            }
        }
    }

    private var defaultHandler: Thread.UncaughtExceptionHandler? = null
    private lateinit var appContext: Context

    fun init(context: Context) {
        appContext = context.applicationContext
        defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
        Thread.setDefaultUncaughtExceptionHandler(this)
        Log.i(TAG, "✅ 崩溃处理器已初始化")
    }

    override fun uncaughtException(thread: Thread, throwable: Throwable) {
        try {
            saveCrashLog(thread, throwable)
        } catch (e: Exception) {
            Log.e(TAG, "❌ 保存崩溃日志失败", e)
        }
        // 交给系统默认处理器（终止进程）
        defaultHandler?.uncaughtException(thread, throwable)
    }

    private fun saveCrashLog(thread: Thread, throwable: Throwable) {
        val timestamp = System.currentTimeMillis()
        val dateFormat = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault())
        val fileName = "crash_${dateFormat.format(Date(timestamp))}_$timestamp.log"

        val sb = StringBuilder()
        // 设备信息
        sb.appendLine("=== 崩溃报告 ===")
        sb.appendLine("时间: ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()).format(Date(timestamp))}")
        sb.appendLine("时间戳: $timestamp")
        sb.appendLine("线程: ${thread.name} (id=${thread.id})")
        sb.appendLine()
        sb.appendLine("=== 设备信息 ===")
        sb.appendLine("品牌: ${Build.BRAND}")
        sb.appendLine("型号: ${Build.MODEL}")
        sb.appendLine("制造商: ${Build.MANUFACTURER}")
        sb.appendLine("Android版本: ${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})")
        sb.appendLine("指纹: ${Build.FINGERPRINT}")
        try {
            val pm = appContext.packageManager
            val pi = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                pm.getPackageInfo(appContext.packageName, android.content.pm.PackageManager.PackageInfoFlags.of(0))
            } else {
                @Suppress("DEPRECATION")
                pm.getPackageInfo(appContext.packageName, 0)
            }
            sb.appendLine("应用版本: ${pi.versionName} (${pi.longVersionCode})")
        } catch (_: Exception) {
            sb.appendLine("应用版本: unknown")
        }
        sb.appendLine("包名: ${appContext.packageName}")
        sb.appendLine()

        // 堆栈信息
        sb.appendLine("=== 异常堆栈 ===")
        val sw = StringWriter()
        throwable.printStackTrace(PrintWriter(sw))
        sb.append(sw.toString())

        // 写入文件
        val crashDir = File(appContext.filesDir, CRASH_DIR)
        if (!crashDir.exists()) crashDir.mkdirs()

        val crashFile = File(crashDir, fileName)
        crashFile.writeText(sb.toString())
        Log.e(TAG, "💾 崩溃日志已保存: ${crashFile.absolutePath}")

        // 清理旧日志
        cleanOldLogs(crashDir)
    }

    private fun cleanOldLogs(dir: File) {
        val files = dir.listFiles { f -> f.name.startsWith("crash_") && f.name.endsWith(".log") }
            ?: return
        if (files.size > MAX_LOG_FILES) {
            files.sortBy { it.lastModified() }
            for (i in 0 until files.size - MAX_LOG_FILES) {
                files[i].delete()
                Log.d(TAG, "🗑️ 清理旧崩溃日志: ${files[i].name}")
            }
        }
    }

    /**
     * 获取崩溃日志目录
     */
    fun getCrashLogDir(): File {
        return File(appContext.filesDir, CRASH_DIR)
    }

    /**
     * 获取所有待上传的崩溃日志文件
     */
    fun getPendingCrashLogs(): List<File> {
        val dir = getCrashLogDir()
        if (!dir.exists()) return emptyList()
        return dir.listFiles { f -> f.name.startsWith("crash_") && f.name.endsWith(".log") }
            ?.sortedByDescending { it.lastModified() }
            ?: emptyList()
    }
}
