package com.convenient.android.common.extension

import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.StatFs
import androidx.core.content.FileProvider
import org.jetbrains.annotations.NotNull
import java.io.File
import java.io.FileFilter
import java.io.FileOutputStream
import java.net.URI
import java.security.DigestInputStream
import java.security.MessageDigest

/**
 * @classname:
 * @author: LiuXiaoLong
 * @date: 2022/7/27
 * description: 文件相关的扩展类
 */

fun File.getUri(context: Context): Uri? {
    return try {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
            Uri.fromFile(this)
        } else {
            FileProvider.getUriForFile(context, context.packageName + ".fileprovider", this)
        }
    } catch (e: Exception) {
        null
    }
}

/**
 * 路径转文件
 */
fun String?.toFile(): File? = this?.let { File(it) }

/**
 * 文件转输出流
 */
fun File.outputStream(append: Boolean = false): FileOutputStream {
    return FileOutputStream(this, append)
}

fun File.byteArrayToHexString() : String = readBytes().toHexString()

/**
 * 重命名
 * @param destName 文件新的名字
 */
fun File.rename(@NotNull destName: String): Boolean {
    if (exists().not() || destName.isEmpty() || destName == name) {
        return false
    }

    val destFile = File(parent + File.separator + destName)

    return !destFile.exists() && renameTo(destFile)
}

/**
 * 如果文件存在则 文件名(+1).后缀
 */
fun File.renameSuffix(): File {
    if (exists()) {
        var destFile: File
        var index = 1
        do {
            destFile = File(parentFile, "${this.nameWithoutExtension}(${index++}).${this.extension}")
        } while (destFile.exists())
        return destFile
    }
    return this
}


/**
 * 移动文件
 * @param targetFile 移动的目标文件
 */
fun File.move(targetFile: File): Boolean {
    return copyTo(targetFile) != null && deleteRecursively()
}


/**
 * 删除文件夹中满足条件的文件或文件夹
 */
fun File.deleteFileWithFilter(filter: FileFilter): Boolean {
    val files = listFiles(filter)
    files?.forEach {
        it.deleteRecursively()
    }
    return true
}

/**
 * 列出文件夹下满足条件的所有文件
 * @param recursively 递归所有文件夹
 * @param accept 满足的条件
 */
fun File.listFilesInDirWithFilter(recursively: Boolean = false, accept: (File) -> Boolean): List<File> {
    return if (recursively) {
        this.walkTopDown().asSequence().filter {
            accept.invoke(it)
        }.toList()
    } else {
        listFiles { file ->
            accept.invoke(file)
        }?.toList() ?: emptyList()
    }
}

/**
 * 列出文件夹下指定格式的所有文件。
 * @param recursively 是否递归所有文件夹进行查找
 */
fun File.listFilesInDirWithExtension(recursively: Boolean, vararg fileExtensions: String): List<File> {
    return listFilesInDirWithFilter(recursively = recursively, accept = {
        fileExtensions.contains(it.extension)
    })
}

/**
 * 列出目录下所有文件夹文件
 */
fun File.listAllDirectoryFiles() : List<File>{
    return listFilesInDirWithFilter {
        it.isDirectory
    }
}

/**
 * 文件的行数
 */
fun File.lines(): Int {
    return readLines().size
}


/**
 * 获取文件夹大小
 */
fun File.getDirLength(): Long {
    var length = 0L
    walkTopDown().asSequence()
        .forEach {
            if (it.isDirectory.not()) {
                length += it.length()
            }
        }
    return length
}

fun File.lengthToFitMemorySize(): String {
    val byteNum = getDirLength()
    return if (byteNum < 0) {
        "0"
    } else if (byteNum < 1024) {
        String.format("%.3fB", byteNum.toDouble())
    } else if (byteNum < 1048576) {
        String.format("%.3fKB", byteNum.toDouble() / 1024)
    } else if (byteNum < 1073741824) {
        String.format("%.3fMB", byteNum.toDouble() / 1048576)
    } else {
        String.format("%.3fGB", byteNum.toDouble() / 1073741824)
    }
}


/**
 * 获取MD5 字节数组
 */
fun File.getMD5Bytes(): ByteArray {
    var md = MessageDigest.getInstance("MD5")
    val dis = DigestInputStream(inputStream(), md)
    return try {
        md = dis.messageDigest
        md.digest()
    } catch (e: Exception) {
        byteArrayOf()
    } finally {
        dis.close()
    }
}

/**
 * 获取md5 字符串
 */
fun File.getMD5(): String {
    return getMD5Bytes().toHexString()
}

/**
 * 获取SD卡剩余存储空间
 */
fun File.getAvailableExternalMemorySize(): Long {
    return if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
        val stat = StatFs(Environment.getExternalStorageDirectory().path)
        stat.availableBlocksLong * stat.blockSizeLong
    } else {
        -1
    }
}





