package com.xyzshell.andinfo.libs

import android.content.Context
import android.os.Environment
import android.os.StatFs
import com.xyzshell.andinfo.libs.storage.models.EncryptionType
import com.xyzshell.andinfo.utils.SystemProperties
import java.io.File

class StorageInfo(private val context: Context) {

    // 内部存储总空间
    val internalStorageTotalSpace: Long
        get() = StatFs(Environment.getDataDirectory().absolutePath).let { statFs ->
            statFs.blockCountLong * statFs.blockSizeLong
        }

    // 内部存储可用空间
    val internalStorageAvailableSpace: Long
        get() = StatFs(Environment.getDataDirectory().absolutePath).let { statFs ->
            statFs.availableBlocksLong * statFs.blockSizeLong
        }

    // 内部存储已使用空间
    val internalStorageUsedSpace: Long
        get() = internalStorageTotalSpace - internalStorageAvailableSpace

    // 内部存储是否加密
    val isInternalStorageEncrypted: Boolean?
        get() = when (SystemProperties.getString("ro.crypto.state", "unknown")) {
            "encrypted" -> true
            "unencrypted" -> false
            else -> null
        }

    // 内部存储加密类型
    val internalStorageEncryptionType: EncryptionType?
        get() = when (SystemProperties.getString("ro.crypto.type", "unknown")) {
            "none" -> EncryptionType.NONE
            "block" -> EncryptionType.FDE
            "file" -> EncryptionType.FBE
            else -> null
        }

    // 内部存储文件系统类型
    val internalStorageFileSystemType: String?
        get() = try {
            // 方法1: 读取 /proc/mounts 文件
            File("/proc/mounts").readLines()
                .find { it.contains(" /data ") }
                ?.split("\\s+".toRegex())
                ?.getOrNull(2)
                ?: run {
                    // 方法2: 使用 StatFs (Android 8.0+)
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                        val statFs = StatFs("/data")
                        statFs.javaClass.getMethod("getFileSystemName").invoke(statFs) as? String
                    } else {
                        null
                    }
                }
        } catch (e: Exception) {
            null
        }

    // /data 目录总大小
    val dataDirectoryTotalSpace: Long
        get() = StatFs("/data").let { statFs ->
            statFs.blockCountLong * statFs.blockSizeLong
        }

    // /data 目录已使用空间
    val dataDirectoryUsedSpace: Long
        get() = StatFs("/data").let { statFs ->
            val total = statFs.blockCountLong * statFs.blockSizeLong
            val available = statFs.availableBlocksLong * statFs.blockSizeLong
            total - available
        }

    // 应用程序和数据占用大小
    val applicationsAndDataSize: Long
        get() = try {
            val dataDir = File("/data/data")
            val appDir = File("/data/app")
            calculateDirectorySize(dataDir) + calculateDirectorySize(appDir)
        } catch (e: Exception) {
            0L
        }

    // 系统占用大小
    val systemSize: Long
        get() = StatFs(Environment.getRootDirectory().absolutePath).let { statFs ->
            statFs.blockCountLong * statFs.blockSizeLong
        }

    // 外部存储总空间
    val externalStorageTotalSpace: Long?
        get() = runCatching {
            StatFs(Environment.getExternalStorageDirectory().absolutePath).let { statFs ->
                statFs.blockCountLong * statFs.blockSizeLong
            }
        }.getOrNull()

    // 外部存储可用空间
    val externalStorageAvailableSpace: Long?
        get() = runCatching {
            StatFs(Environment.getExternalStorageDirectory().absolutePath).let { statFs ->
                statFs.availableBlocksLong * statFs.blockSizeLong
            }
        }.getOrNull()

    // 外部存储已使用空间
    val externalStorageUsedSpace: Long?
        get() = externalStorageTotalSpace?.let { total ->
            externalStorageAvailableSpace?.let { available ->
                total - available
            }
        }

    // 外部存储是否为模拟存储
    val isExternalStorageEmulated: Boolean
        get() = Environment.isExternalStorageEmulated()

    // 外部存储是否可移除
    val isExternalStorageRemovable: Boolean
        get() = Environment.isExternalStorageRemovable()

    // 是否支持可更新的 APEX
    val hasUpdatableApex: Boolean?
        get() = SystemProperties.getBoolean("ro.apex.updatable")

    // 是否使用 system-as-root 分区方案
    val usesSystemAsRoot: Boolean?
        get() = SystemProperties.getBoolean("ro.build.system_root_image")

    // 是否使用 A/B 分区更新方案
    val usesAb: Boolean?
        get() = SystemProperties.getBoolean("ro.build.ab_update")

    // A/B OTA 分区列表
    val abOtaPartitions: Array<String>?
        get() = SystemProperties.getString("ro.product.ab_ota_partitions")?.split(",")?.toTypedArray()

    // 是否使用动态分区
    val usesDynamicPartitions: Boolean?
        get() = SystemProperties.getBoolean("ro.boot.dynamic_partitions")

    // 是否使用改造的动态分区
    val usesRetrofittedDynamicPartitions: Boolean?
        get() = SystemProperties.getBoolean("ro.boot.dynamic_partitions_retrofit")

    // 是否使用虚拟 A/B 分区
    val usesVirtualAb: Boolean?
        get() = SystemProperties.getBoolean("ro.virtual_ab.enabled")

    // 是否使用改造的虚拟 A/B 分区
    val usesRetrofittedVirtualAb: Boolean?
        get() = SystemProperties.getBoolean("ro.virtual_ab.retrofit")

    // 虚拟 A/B 分区是否启用压缩
    val usesCompressedVirtualAb: Boolean?
        get() = SystemProperties.getBoolean("ro.virtual_ab.compression.enabled")

    // 计算目录大小(递归)
    private fun calculateDirectorySize(directory: File): Long {
        var size = 0L
        try {
            if (directory.exists() && directory.isDirectory) {
                directory.listFiles()?.forEach { file ->
                    size += if (file.isDirectory) {
                        calculateDirectorySize(file)
                    } else {
                        file.length()
                    }
                }
            }
        } catch (e: Exception) {
            // 可能因权限问题无法访问某些目录
        }
        return size
    }

    // 格式化存储大小
    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))
        }
    }
}
