package com.xyzshell.andinfo.libs

import android.content.Context
import java.io.File
import java.io.RandomAccessFile

data class MemoryInfo(
    val totalRam: Long,          // 总内存 (字节)
    val availableRam: Long,      // 可用内存 (字节)
    val usedRam: Long,           // 已使用内存 (字节)
    val memType: String,         // 内存类型 (LPDDR4/LPDDR5等)
    val channels: Int,           // 内存通道数
    val zramTotal: Long,         // zram 总大小 (字节)
    val zramUsed: Long           // zram 已使用 (字节)
)

class MemInfo(private val context: Context){

    fun getMemoryInfo(): MemoryInfo {
        val totalRam = getTotalMemory()
        val availableRam = getAvailableMemory()
        val usedRam = totalRam - availableRam
        val memType = getMemoryType()
        val channels = getMemoryChannels()
        val (zramTotal, zramUsed) = getZramInfo()

        return MemoryInfo(
            totalRam = totalRam,
            availableRam = availableRam,
            usedRam = usedRam,
            memType = memType,
            channels = channels,
            zramTotal = zramTotal,
            zramUsed = zramUsed
        )
    }

    private fun getTotalMemory(): Long {
        return try {
            val memInfo = File("/proc/meminfo")
            memInfo.readLines().find { it.startsWith("MemTotal:") }?.let {
                it.split("\\s+".toRegex())[1].toLong() * 1024
            } ?: 0L
        } catch (e: Exception) {
            0L
        }
    }

    private fun getAvailableMemory(): Long {
        return try {
            val memInfo = File("/proc/meminfo")
            memInfo.readLines().find { it.startsWith("MemAvailable:") }?.let {
                it.split("\\s+".toRegex())[1].toLong() * 1024
            } ?: 0L
        } catch (e: Exception) {
            0L
        }
    }

    private fun getMemoryType(): String {
        return try {
            // 尝试从多个可能的位置读取
            val paths = listOf(
                "/sys/class/devfreq/ddrfreq/device/type",
                "/sys/class/devfreq/soc:qcom,cpu-cpu-llcc-bw/device/type",
                "/proc/device-tree/memory/device_type"
            )

            for (path in paths) {
                val file = File(path)
                if (file.exists()) {
                    val content = file.readText().trim()
                    if (content.isNotEmpty()) {
                        return content
                    }
                }
            }

            // 尝试从 getprop 获取
            Runtime.getRuntime().exec("getprop ro.boot.ddr_type").inputStream.bufferedReader().readText().trim()
                .ifEmpty { "Unknown" }
        } catch (e: Exception) {
            "Unknown"
        }
    }

    private fun getMemoryChannels(): Int {
        return try {
            // 尝试从设备树或内核日志获取
            val dmesgChannels = Runtime.getRuntime()
                .exec("dmesg | grep -i 'memory.*channel'")
                .inputStream.bufferedReader().readText()

            // 解析通道数,默认返回 2
            when {
                dmesgChannels.contains("dual", ignoreCase = true) -> 2
                dmesgChannels.contains("quad", ignoreCase = true) -> 4
                dmesgChannels.contains("single", ignoreCase = true) -> 1
                else -> 2 // 默认双通道
            }
        } catch (e: Exception) {
            2
        }
    }

    private fun getZramInfo(): Pair<Long, Long> {
        return try {
            var total = 0L
            var used = 0L

            // 检查所有 zram 设备
            for (i in 0..7) {
                val devicePath = "/sys/block/zram$i"
                if (!File(devicePath).exists()) continue

                // 读取总大小
                File("$devicePath/disksize").readText().trim().toLongOrNull()?.let {
                    total += it
                }

                // 读取已使用大小
                File("$devicePath/mem_used_total").readText().trim().toLongOrNull()?.let {
                    used += it
                }
            }

            Pair(total, used)
        } catch (e: Exception) {
            Pair(0L, 0L)
        }
    }

    // 格式化内存大小
    fun formatBytes(bytes: Long): String {
        return when {
            bytes < 1024 -> "$bytes B"
            bytes < 1024 * 1024 -> String.format("%.2f KB", bytes / 1024.0)
            bytes < 1024 * 1024 * 1024 -> String.format("%.2f MB", bytes / (1024.0 * 1024))
            else -> String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024))
        }
    }
}