package com.rosetta.messenger.utils

import android.content.Context
import android.os.Build
import java.io.File
import java.io.PrintWriter
import java.io.StringWriter
import java.text.SimpleDateFormat
import java.util.*

/**
 * Менеджер для сохранения crash reports в локальное хранилище
 */
class CrashReportManager private constructor(private val context: Context) : Thread.UncaughtExceptionHandler {
    
    private val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
    private val dateFormat = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault())
    
    companion object {
        private const val TAG = "CrashReportManager"
        private const val CRASH_DIR = "crash_reports"
        private const val MAX_CRASH_FILES = 50 // Максимум файлов с крашами
        
        @Volatile
        private var INSTANCE: CrashReportManager? = null
        
        /**
         * Инициализация crash reporter
         */
        fun init(context: Context) {
            if (INSTANCE == null) {
                synchronized(this) {
                    if (INSTANCE == null) {
                        INSTANCE = CrashReportManager(context.applicationContext)
                        Thread.setDefaultUncaughtExceptionHandler(INSTANCE)
                    }
                }
            }
        }
        
        /**
         * Получить список всех crash reports
         */
        fun getCrashReports(context: Context): List<CrashReport> {
            val crashDir = File(context.filesDir, CRASH_DIR)
            if (!crashDir.exists()) return emptyList()

            val reports = crashDir.listFiles()
                ?.filter { it.extension == "txt" }
                ?.sortedByDescending { it.lastModified() }
                ?.map { file ->
                    CrashReport(
                        fileName = file.name,
                        timestamp = file.lastModified(),
                        content = file.readText()
                    )
                }?.toMutableList() ?: mutableListOf()

            // Include native crash report if present
            val nativeCrash = File(crashDir, "native_crash.txt")
            if (nativeCrash.exists() && nativeCrash.length() > 0) {
                reports.add(0, CrashReport(
                    fileName = "native_crash.txt",
                    timestamp = nativeCrash.lastModified(),
                    content = nativeCrash.readText()
                ))
                // Delete after reading so it doesn't show up again
                nativeCrash.delete()
            }

            return reports
        }
        
        /**
         * Удалить старые crash reports
         */
        fun deleteCrashReport(context: Context, fileName: String): Boolean {
            val crashDir = File(context.filesDir, CRASH_DIR)
            val file = File(crashDir, fileName)
            return if (file.exists()) {
                file.delete()
            } else {
                false
            }
        }
        
        /**
         * Удалить все crash reports
         */
        fun deleteAllCrashReports(context: Context) {
            val crashDir = File(context.filesDir, CRASH_DIR)
            if (crashDir.exists()) {
                crashDir.listFiles()?.forEach { it.delete() }
            }
        }
    }
    
    override fun uncaughtException(thread: Thread, throwable: Throwable) {
        try {
            saveCrashReport(thread, throwable)
        } catch (e: Exception) {
        }
        
        // Вызываем дефолтный handler (чтобы система тоже обработала краш)
        defaultHandler?.uncaughtException(thread, throwable)
    }
    
    /**
     * Сохранить crash report в файл
     */
    private fun saveCrashReport(thread: Thread, throwable: Throwable) {
        val timestamp = dateFormat.format(Date())
        val fileName = "crash_$timestamp.txt"
        
        val crashDir = File(context.filesDir, CRASH_DIR)
        if (!crashDir.exists()) {
            crashDir.mkdirs()
        }
        
        val crashFile = File(crashDir, fileName)
        
        val report = buildCrashReport(thread, throwable)
        crashFile.writeText(report)
        
        
        // Удаляем старые файлы если их слишком много
        cleanupOldCrashFiles(crashDir)
    }
    
    /**
     * Собрать информацию о краше
     */
    private fun buildCrashReport(thread: Thread, throwable: Throwable): String {
        val report = StringBuilder()
        
        // Заголовок
        report.append("=== CRASH REPORT ===\n\n")
        
        // Время краша
        report.append("Timestamp: ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())}\n\n")
        
        // Информация о приложении
        report.append("=== App Info ===\n")
        report.append("Package: ${context.packageName}\n")
        try {
            val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
            report.append("Version: ${packageInfo.versionName} (${packageInfo.longVersionCode})\n")
        } catch (e: Exception) {
            report.append("Version: Unknown\n")
        }
        report.append("\n")
        
        // Информация об устройстве
        report.append("=== Device Info ===\n")
        report.append("Manufacturer: ${Build.MANUFACTURER}\n")
        report.append("Model: ${Build.MODEL}\n")
        report.append("Android Version: ${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})\n")
        report.append("Device: ${Build.DEVICE}\n")
        report.append("Board: ${Build.BOARD}\n")
        report.append("\n")
        
        // Информация о треде
        report.append("=== Thread Info ===\n")
        report.append("Thread: ${thread.name}\n")
        report.append("Thread ID: ${thread.id}\n")
        report.append("\n")
        
        // Stack trace
        report.append("=== Exception ===\n")
        report.append("Exception Type: ${throwable.javaClass.name}\n")
        report.append("Message: ${throwable.message ?: "No message"}\n\n")
        
        // Полный stack trace
        report.append("=== Stack Trace ===\n")
        val stringWriter = StringWriter()
        val printWriter = PrintWriter(stringWriter)
        throwable.printStackTrace(printWriter)
        report.append(stringWriter.toString())
        
        // Cause (если есть)
        var cause = throwable.cause
        var causeLevel = 1
        while (cause != null) {
            report.append("\n=== Caused by (level $causeLevel) ===\n")
            report.append("Exception Type: ${cause.javaClass.name}\n")
            report.append("Message: ${cause.message ?: "No message"}\n\n")
            
            val causeWriter = StringWriter()
            val causePrintWriter = PrintWriter(causeWriter)
            cause.printStackTrace(causePrintWriter)
            report.append(causeWriter.toString())
            
            cause = cause.cause
            causeLevel++
            
            // Предотвращаем бесконечный цикл
            if (causeLevel > 10) break
        }
        
        return report.toString()
    }
    
    /**
     * Удалить старые crash файлы если их слишком много
     */
    private fun cleanupOldCrashFiles(crashDir: File) {
        val files = crashDir.listFiles()?.sortedByDescending { it.lastModified() } ?: return
        
        if (files.size > MAX_CRASH_FILES) {
            files.drop(MAX_CRASH_FILES).forEach { file ->
                file.delete()
            }
        }
    }
    
    /**
     * Data class для представления crash report
     */
    data class CrashReport(
        val fileName: String,
        val timestamp: Long,
        val content: String
    )
}
