package com.duben.microtribe.utils

import android.app.ActivityManager
import android.content.Context
import android.os.Environment
import android.os.StatFs
import com.duben.microtribe.MintsApplication
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
import java.io.IOException
import kotlin.math.ceil


object SystemUtils {

    /**
     * 该方法必须在Activity或Service类内调用，一般情况下，可以在Activity的onCreate()方法中调用。
     * 由于应用每启动一个新的进程，就会调用一次Application的onCreate()方法，而个推SDK是一个独立的进程
     * ，因此如果在Application的onCreate()中调用intialize接口，会导致SDK初始化在一个应用中多次调用，
     * 所以不建议在Application继承类中调用个推SDK初始化接口。
     * 解释一下，每个[Android](http://lib.csdn.net/base/android "Android知识库")应用都要运行在一个虚拟机上，
     * ”个推“采用Service和后台服务器通信进行通信，于是和原本的Activity就形成了多进程。
     * 一个前台的应用进程，一个service后台进程，每个进程对应一个application对象，所以当应用配置了多个进程的时候，
     * application对象的onCreate方法就会执行多次，所以为了保证只初始化一次，
     * 就必须做出区分的处理的（“个推”中提到的在Activity或Service中初始，这种做法个人认为也是存在多次初始化的风险的）；
     * 进程名是通过Manifest.xml中的"android:process"属性设置的，因此可以在application的onCreate方法中通过pid获取processName，
     * 再做进一步的判断（跟android:process的值进行判断）使得相关初始化代码仅执行一次。
     */
    fun getProcessName(cxt: Context, pid: Int): String? {
        val am: ActivityManager = cxt.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val runningApps: List<ActivityManager.RunningAppProcessInfo> =
            am.runningAppProcesses
                ?: return null
        for (procInfo in runningApps) {
            if (procInfo.pid == pid) {
                return procInfo.processName
            }
        }
        return null
    }

    /**
     * ram
     */
    fun getTotalMemory(): String {
        // 系统内存信息文件
        val file = "/proc/meminfo"
        val memInfo: String
        val strs: Array<String>
        var memory: Long = 0
        try {
            val fileReader = FileReader(file)
            val bufferedReader = BufferedReader(
                fileReader,
                8192
            )
            // 读取meminfo第一行，系统内存大小
            memInfo = bufferedReader.readLine()
            strs = memInfo.split("\\s+".toRegex()).toTypedArray()
            // 获得系统总内存，单位KB
            memory = Integer.valueOf(strs[1]).toLong()
            bufferedReader.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return "" + ceil((memory.toFloat() / (1024 * 1024).toDouble())).toInt() + "GB"
    }

    /**
     * 获取手机内部空间总大小
     *
     * @return 大小，字节为单位
     */
    fun getTotalInternalMemorySize(): String {
        //获取内部存储根目录
        val path: File = Environment.getExternalStorageDirectory()
        //系统的空间描述类
        val stat = StatFs(path.absolutePath)
        //每个区块占字节数
        val totalSize = stat.totalBytes
        return "" + ceil((totalSize.toFloat() / (1024 * 1024 * 1024).toDouble())).toInt() + "GB"
    }

    /**
     * 描述：获取存储占用率.
     */
    fun getUsedStorageValue(): Int {
        return (getAvailableMemorySize() / getTotalInternalMemoryLongSize()).toInt()
    }

    /**
     * 获取手机内部空间总大小
     *
     * @return 大小，字节为单位
     */
    fun getTotalInternalMemoryLongSize(): Long {
        //获取内部存储根目录
        val path: File = Environment.getExternalStorageDirectory()
        //系统的空间描述类
        val stat = StatFs(path.absolutePath)
        //每个区块占字节数
        return stat.totalBytes
    }


    /**
     * 获取手机剩余存储空间
     *
     * @return byte
     */
    fun getAvailableMemorySize(): Long {
        try {
            var sumMemorySize = 0L
            if (externalMemoryAvailable()) {
                sumMemorySize += getAvailableExternalMemorySize()
            }
            sumMemorySize += getAvailableInternalMemorySize()
            return sumMemorySize
        } catch (e: java.lang.Exception) {
            return 0L
        }
    }

    /**
     * 获取手机内部剩余存储空间 外部存储空间
     *
     * 1.硬件上的 block size, 应该是"sector size"，linux的扇区大小是512byte
     * 2.有文件系统的分区的block size, 是"block size"，大小不一，可以用工具查看
     * 3.没有文件系统的分区的block size，也叫“block size”，大小指的是1024 byte
     * 4.Kernel buffer cache 的block size, 就是"block size"，大部分PC是1024
     * 5.磁盘分区的"cylinder size"，用fdisk 可以查看
     *
     * @return byte
     */
    fun getAvailableExternalMemorySize(): Long {
        val path = Environment.getDataDirectory()
        val stat = StatFs(path.path)
        val blockSize = stat.blockSizeLong
        //        val blockCount = sf.blockCount.toLong()
        val availableBlocks = stat.availableBlocksLong
        return availableBlocks * blockSize
    }

    /**
     * SDCARD是否存在
     */
    fun externalMemoryAvailable(): Boolean {
        return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
    }

    /**
     * 获取手机内部剩余存储空间 内部存储空间
     *
     * @return byte
     */
    fun getAvailableInternalMemorySize(): Long {
        val root = Environment.getRootDirectory()
        val sf = StatFs(root.path)
        val blockSize = sf.blockSizeLong
        //        val blockCount = sf.blockCount.toLong()
        val availableBlocks = sf.availableBlocksLong
        return availableBlocks * blockSize
    }

    /**
     * 描述：获取内存占用率.
     */
    fun getUsedPercentValue(context: Context?): Int {
        val dir = "/proc/meminfo"
        try {
            val fr = FileReader(dir)
            val br = BufferedReader(fr, 8192)
            val memoryTotalLine = br.readLine()
            val subMemoryLine = memoryTotalLine.substring(memoryTotalLine.indexOf("MemTotal:"))
            /** KB 计量单位 */
            br.close()

//            LogUtil.d(subMemoryLine)

            val totalMemorySize = subMemoryLine.replace("\\D+".toRegex(), "").toLong() * 1024

//            LogUtil.d(subMemoryLine.replace("\\D+".toRegex(), "").toLong())

            val availableSize: Long = getAvailMemory(context)
            return (((totalMemorySize - availableSize) / totalMemorySize.toFloat()) * 100).toInt()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return 80
    }

    /**
     * 描述：获取可用内存.
     */
    fun getAvailMemory(context: Context?): Long {
        // 获取android当前可用内存大小
        val activityManager = context?.getSystemService(
            Context.ACTIVITY_SERVICE
        ) as ActivityManager
        val memoryInfo =
            ActivityManager.MemoryInfo()
        activityManager.getMemoryInfo(memoryInfo)
        // 当前系统可用内存 ,将获得的内存大小规格化
        return memoryInfo.availMem
    }

    fun getBatteryCapacity(): String? {
        val mPowerProfile: Any
        var batteryCapacity = 0.0
        //电池的容量mAhfinal
        val POWER_PROFILE_CLASS = "com.android.internal.os.PowerProfile"
        try {
            mPowerProfile = Class.forName(POWER_PROFILE_CLASS).getConstructor(Context::class.java)
                .newInstance(MintsApplication.getContext())
            batteryCapacity = Class.forName(POWER_PROFILE_CLASS).getMethod("getBatteryCapacity")
                .invoke(mPowerProfile) as Double
        } catch (e: java.lang.Exception) {
            return "unknown"
        }
        return batteryCapacity.toInt().toString() + "mA"
    }

}