package top.yeij.cyrene.util

import android.content.Context
import android.content.Intent
import androidx.core.content.FileProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream

enum class LogCategory(val label: String) {
    CHAT("聊天"),
    WS("WebSocket"),
    STT("语音识别"),
    GENERAL("通用"),
    HTTP("网络"),
    VOICE("语音"),
    NOTIFY("通知"),
}

data class LogEntry(
    val timestamp: Long,
    val category: LogCategory,
    val tag: String,
    val message: String,
) {
    fun formatted(): String {
        val sdf = SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault())
        return "[${sdf.format(Date(timestamp))}] [${category.name}] [$tag] $message"
    }
}

object RuntimeLog {

    private const val MAX_ENTRIES = 2000

    private val _entries = MutableStateFlow<List<LogEntry>>(emptyList())
    val entries: StateFlow<List<LogEntry>> = _entries.asStateFlow()

    private val buffer = ArrayDeque<LogEntry>(MAX_ENTRIES)

    @Synchronized
    fun log(category: LogCategory, tag: String, message: String) {
        val entry = LogEntry(System.currentTimeMillis(), category, tag, message)
        if (buffer.size >= MAX_ENTRIES) {
            buffer.removeFirst()
        }
        buffer.addLast(entry)
        _entries.value = buffer.toList()
    }

    fun chat(tag: String, message: String) = log(LogCategory.CHAT, tag, message)
    fun ws(tag: String, message: String) = log(LogCategory.WS, tag, message)
    fun stt(tag: String, message: String) = log(LogCategory.STT, tag, message)
    fun general(tag: String, message: String) = log(LogCategory.GENERAL, tag, message)
    fun http(tag: String, message: String) = log(LogCategory.HTTP, tag, message)
    fun voice(tag: String, message: String) = log(LogCategory.VOICE, tag, message)
    fun notify(tag: String, message: String) = log(LogCategory.NOTIFY, tag, message)

    @Synchronized
    fun getByCategory(category: LogCategory): List<LogEntry> {
        return buffer.filter { it.category == category }
    }

    @Synchronized
    fun exportAsText(category: LogCategory): String {
        val entries = buffer.filter { it.category == category }
        val header = "=== Cyrene ${category.label}日志 导出时间: ${
            SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
        } ===\n\n"
        return header + entries.joinToString("\n") { it.formatted() }
    }

    @Synchronized
    fun exportAllAsText(): String {
        val header = "=== Cyrene 全部日志 导出时间: ${
            SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
        } ===\n\n"
        val byCategory = buffer.groupBy { it.category }
        return header + byCategory.entries.joinToString("\n\n") { (cat, entries) ->
            "--- ${cat.label} (${cat.name}) ---\n" + entries.joinToString("\n") { it.formatted() }
        }
    }

    fun exportToFile(context: Context, category: LogCategory? = null): File {
        val text = if (category != null) exportAsText(category) else exportAllAsText()
        val label = category?.name?.lowercase() ?: "all"
        val dateStr = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
        val file = File(context.cacheDir, "cyrene_log_${label}_$dateStr.txt")
        file.writeText(text)
        return file
    }

    fun exportAllAsZip(context: Context): File {
        val dateStr = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
        val zipFile = File(context.cacheDir, "cyrene_logs_$dateStr.zip")
        ZipOutputStream(zipFile.outputStream().buffered()).use { zos ->
            LogCategory.entries.forEach { cat ->
                val text = exportAsText(cat)
                zos.putNextEntry(ZipEntry("${cat.name.lowercase()}.txt"))
                zos.write(text.toByteArray(Charsets.UTF_8))
                zos.closeEntry()
            }
        }
        return zipFile
    }

    fun shareFile(context: Context, file: File) {
        val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
        val intent = Intent(Intent.ACTION_SEND).apply {
            type = if (file.extension == "zip") "application/zip" else "text/plain"
            putExtra(Intent.EXTRA_STREAM, uri)
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        }
        context.startActivity(Intent.createChooser(intent, "导出日志"))
    }

    @Synchronized
    fun clear() {
        buffer.clear()
        _entries.value = emptyList()
    }
}
