package com.base.superfilemanager.helps

import android.app.usage.StorageStats
import android.app.usage.StorageStatsManager
import android.content.Context
import android.content.pm.IPackageStatsObserver
import android.content.pm.PackageManager
import android.content.pm.PackageStats
import android.os.Build
import android.os.storage.StorageManager
import android.text.format.Formatter
import androidx.annotation.RequiresApi
import java.io.IOException
import java.util.UUID

/**
 *获取APP应用  缓存大小 数据大小 应用大小
 * aidl的方式反射系统api
 */
class AppSizeUtils private constructor() {

    private val TAG = "AppSizeUtils"

    /**
     * 打印大小
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun printStorageStats(context: Context, packageName: String, storageStats: StorageStats?) {
        if (storageStats != null) {
            val cacheBytesF = Formatter.formatFileSize(context, storageStats.cacheBytes)
            val dataBytesF = Formatter.formatFileSize(context, storageStats.cacheBytes)
            val appBytesF = Formatter.formatFileSize(context, storageStats.cacheBytes)
            val size = storageStats.cacheBytes + storageStats.dataBytes + storageStats.appBytes
            val total = Formatter.formatFileSize(context, size)
            val log = "$packageName StorageStats cacheBytesF=$cacheBytesF dataBytesF=$dataBytesF appBytesF=$appBytesF total=$total"
            LogEx.logDebug(TAG, log)
        }
    }

    fun printPackageStats(context: Context, packageName: String, packageStats: PackageStats?) {
        if (packageStats != null) {
            val cacheSizeF = Formatter.formatFileSize(context, packageStats.cacheSize)
            val dataSizeF = Formatter.formatFileSize(context, packageStats.dataSize)
            val codeSizeF = Formatter.formatFileSize(context, packageStats.codeSize)
            val size = packageStats.cacheSize + packageStats.dataSize + packageStats.codeSize
            val total = Formatter.formatFileSize(context, size)

            val log = "$packageName PackageStats cacheSizeF=$cacheSizeF dataSizeF=$dataSizeF codeSizeF=$codeSizeF total=$total"
            LogEx.logDebug(TAG, log)
        }
    }

    /**
     * 获取应用的大小
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    fun getAppSizeO(context: Context, packageName: String): Long {
        val storageStatsManager = context.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager
        val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
        //获取所有应用的StorageVolume列表
        val storageVolumes = storageManager.getStorageVolumes()
        for (item in storageVolumes) {
            val uuidStr = item.uuid
            val uuid: UUID = if (uuidStr == null) {
                StorageManager.UUID_DEFAULT
            } else {
                UUID.fromString(uuidStr)
            }
            val uid = getUid(context, packageName)
            //通过包名获取uid
            var storageStats: StorageStats? = null
            try {
                storageStats = storageStatsManager.queryStatsForUid(uuid, uid)
            } catch (e: IOException) {
                e.printStackTrace()
            }
            if (storageStats != null) {
                val size = storageStats.cacheBytes + storageStats.dataBytes + storageStats.appBytes
                printStorageStats(context, packageName, storageStats)
                return size
            }
        }
        return 0
    }


    /**
     * 根据应用包名获取对应uid
     */
    fun getUid(context: Context, pakName: String?): Int {
        try {
            return context.packageManager.getApplicationInfo(pakName!!, PackageManager.GET_META_DATA).uid
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
        return -1
    }

    /**
     * 获取应用大小8.0以下
     */
    fun getAppSize(context: Context, packageName: String): Long {
        var size = 0L
        try {
            val method =
                PackageManager::class.java.getMethod("getPackageSizeInfo", String::class.java, IPackageStatsObserver::class.java)
            // 调用 getPackageSizeInfo 方法，需要两个参数：1、需要检测的应用包名；2、回调
            method.invoke(context.packageManager, packageName, object : IPackageStatsObserver.Stub() {
                override fun onGetStatsCompleted(pStats: PackageStats, succeeded: Boolean) {
                    size = pStats.cacheSize + pStats.dataSize + pStats.codeSize
                    printPackageStats(context, packageName, pStats)
                }
            })
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return size
    }


    companion object {
        private var mApiUrl: AppSizeUtils? = null
        val instance: AppSizeUtils?
            get() {
                if (mApiUrl == null) {
                    synchronized(AppSizeUtils::class.java) {
                        if (mApiUrl == null) {
                            mApiUrl = AppSizeUtils()
                        }
                    }
                }
                return mApiUrl
            }
    }
}
