package com.cheng.blzb.utils

import android.annotation.SuppressLint
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.FileUtils
import android.os.StatFs
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.text.TextUtils
import androidx.annotation.RequiresApi
import com.example.base.extensions.toast
import com.example.base.utils.L
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream

object FileProviderUtils {
    //文件夹的名称
    private const val dirName = "UploadFile"

    /**
     * 根据Uri获取文件绝对路径，解决Android4.4以上版本Uri转换 兼容Android 10
     *
     * @param context
     * @param uri
     * @param fileName 自定义沙盒的文件名,避免沙盒中同名的情况,另外要注意的一点是沙盒中的文件记得要删除
     */
    fun getFileAbsolutePath(context: Context, uri: Uri, fileName: String = ""): String? {
        //大于等于Android 19,小于Android 29
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && DocumentsContract.isDocumentUri(context, uri)) {
            if (isExternalStorageDocument(uri)) {
                val docId: String = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":")
                val type = split[0]
                if ("primary" == type) {
                    return "${Environment.getExternalStorageDirectory()}/${split[1]}"
                }
            } else if (isDownloadsDocument(uri)) {
                val id = DocumentsContract.getDocumentId(uri)
                return if (!TextUtils.isEmpty(id)) {
                    if (id.startsWith("raw:")) {
                        id.replaceFirst("raw:", "")
                    } else {
                        try {
                            getContentPath(context, id)
                        } catch (exception: NumberFormatException) {
                            null
                        }
                    }
                } else {
                    null
                }
            } else if (isMediaDocument(uri)) {
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":")
                val type = split[0]
                var contentUri: Uri? = null
                when (type) {
                    "image" -> {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                    }

                    "video" -> {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                    }

                    "audio" -> {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                    }

                    else -> {}
                }
                val selection = "${MediaStore.Images.Media._ID}=?"
                val selectionArgs = arrayOf(split[1])
                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }

        // MediaStore (and general)
        //大于Android 29
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return if (fileName.isNotEmpty()) {
                uriToFileApiQCustomFileName(context, uri, fileName)
            } else {
                uriToFileApiQ(context, uri)
            }
        } else if ("content" == uri.scheme) {
            // Return the remote address
            if (isGooglePhotosUri(uri)) {
                return uri.lastPathSegment;
            }
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file" == uri.scheme) {
            return uri.path
        }
        return null
    }

    /**
     * 获取download文件夹存储内容的路径
     */
    private fun getContentPath(context: Context, id: String): String? {
        val contentUriPrefixesToTry = arrayOf(
            "content://downloads/public_downloads",
            "content://downloads/my_downloads",
            "content://downloads/all_downloads"
        )

        for (contentUriPrefix in contentUriPrefixesToTry) {
            val contentUri =
                ContentUris.withAppendedId(Uri.parse(contentUriPrefix), id.toLong())
            try {
                val path = getDataColumn(context, contentUri, null, null)
                if (path != null) {
                    return path
                }
            } catch (_: java.lang.Exception) {

            }
        }
        return null
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    private fun isExternalStorageDocument(uri: Uri): Boolean {
        return "com.android.externalstorage.documents" == uri.authority
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    private fun isDownloadsDocument(uri: Uri): Boolean {
        return "com.android.providers.downloads.documents" == uri.authority
    }

    private fun getDataColumn(
        context: Context,
        uri: Uri?,
        selection: String?,
        selectionArgs: Array<String>?
    ): String? {
        var cursor: Cursor? = null
        val column: String = MediaStore.Images.Media.DATA
        val projection = arrayOf(column)
        if (uri != null) {
            try {
                cursor =
                    context.contentResolver.query(uri, projection, selection, selectionArgs, null)
                if (cursor != null && cursor.moveToFirst()) {
                    val index: Int = cursor.getColumnIndexOrThrow(column)
                    return cursor.getString(index);
                }
            } catch (exception: IllegalArgumentException) {
                return getFilePathFromURI(context, uri)
            } finally {
                cursor?.close()
            }
        }
        return null
    }

    /**
     * 获取文件路径
     */
    private fun getFilePathFromURI(context: Context, uri: Uri): String? {
        val fileName = getFileName(uri)
        if (!TextUtils.isEmpty(fileName)) {
            val copyFile = File(context.cacheDir, fileName!!)
            copyCacheFile(context, uri, copyFile)
            return copyFile.absolutePath
        }
        return null
    }

    /**
     * 获取文件名
     */
    private fun getFileName(uri: Uri): String? {
        var fileName: String? = null
        uri.path?.let { path ->
            path.lastIndexOf('/').also {
                if (it != -1) {
                    fileName = path.substring(it + 1)
                }
            }
        }
        return fileName
    }

    /**
     * 复制文件
     */
    private fun copyCacheFile(context: Context, uri: Uri, copyFile: File) {
        try {
            val inputStream = context.contentResolver.openInputStream(uri)
            val outputStream = FileOutputStream(copyFile)
            val buffer = ByteArray(1024)
            var length: Int

            if (inputStream != null) {
                while (inputStream.read(buffer).also { length = it } > 0) {
                    outputStream.write(buffer, 0, length)
                }
                outputStream.flush()
                inputStream.close()
                outputStream.close()
            }
        } catch (exception: IOException) {
            L.e(exception.message)
        }
    }


    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    private fun isMediaDocument(uri: Uri): Boolean {
        return "com.android.providers.media.documents" == uri.authority
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is Google Photos.
     */
    private fun isGooglePhotosUri(uri: Uri): Boolean {
        return "com.google.android.apps.photos.content" == uri.authority
    }


    /**
     * Android 10 以上适配 另一种写法
     * @param context
     * @param uri
     * @return
     */
    @SuppressLint("Range")
    private fun getFileFromContentUri(context: Context, uri: Uri): String? {
        val filePath: String?
        val filePathColumn =
            arrayOf(MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DISPLAY_NAME)
        val contentResolver: ContentResolver = context.contentResolver
        val cursor: Cursor? = contentResolver.query(
            uri, filePathColumn, null,
            null, null
        )
        if (cursor != null) {
            cursor.moveToFirst()
            try {
                filePath = cursor.getString(cursor.getColumnIndex(filePathColumn[0]))
                return filePath
            } catch (e: Exception) {
                L.d(e.message)
            } finally {
                cursor.close()
            }
        }
        return ""
    }

    /**
     * Android 10 以上适配
     * @param context
     * @param uri
     * @return
     */
    @SuppressLint("Range")
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private fun uriToFileApiQ(context: Context, uri: Uri): String? {
        var file: File? = null
        //android10以上转换
        if (uri.scheme.equals(ContentResolver.SCHEME_FILE)) {
            file = File(uri.path!!)
        } else if (uri.scheme.equals(ContentResolver.SCHEME_CONTENT)) {
            val contentResolver: ContentResolver = context.contentResolver
            val cursor: Cursor? = contentResolver.query(uri, null, null, null, null)
            try {
                //把文件复制到沙盒目录
                if (cursor != null) {
                    if (cursor.moveToFirst()) {
                        //通过Cursor获取真实的文件名
                        val displayName: String = cursor.getString(
                            cursor.getColumnIndex(
                                OpenableColumns.DISPLAY_NAME
                            )
                        )
                        val fileSize = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE))
                        //判断存储空间是否足够
                        if (getRemainingStorageSpace() <= fileSize) {
                            toast("空间不足")
                            return null
                        }

                        val inputStream: InputStream? = contentResolver.openInputStream(uri)
                        //在沙盒中存储也是用的真实的文件名
                        val pathFile = File(context.getExternalFilesDir(null), dirName)
                        if (!pathFile.exists()) {
                            pathFile.mkdir()
                        }
                        val cache = File(pathFile, displayName)
                        val fos = FileOutputStream(cache)
                        if (inputStream != null) {
                            FileUtils.copy(inputStream, fos)
                        }
                        file = cache
                        fos.close()
                        inputStream?.close()
                    }

                }
            } catch (e: Exception) {
                e.printStackTrace();
            } finally {
                cursor?.close()
            }

        }
        return file?.absolutePath
    }

    /**
     * Android 10 以上适配
     * @param context
     * @param uri
     * @return
     */
    @SuppressLint("Range")
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private fun uriToFileApiQCustomFileName(context: Context, uri: Uri, fileName: String): String? {
        var file: File? = null
        //android10以上转换
        if (uri.scheme.equals(ContentResolver.SCHEME_FILE)) {
            file = File(uri.path!!)
        } else if (uri.scheme.equals(ContentResolver.SCHEME_CONTENT)) {
            //把文件复制到沙盒目录
            val contentResolver: ContentResolver = context.contentResolver
            val cursor: Cursor? = contentResolver.query(uri, null, null, null, null)
            try {
                if (cursor != null) {
                    if (cursor.moveToFirst()) {
                        val fileSize = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE))
                        //判断存储空间是否足够
                        if (getRemainingStorageSpace() <= fileSize) {
                            toast("空间不足")
                            return null
                        }

                        val inputStream: InputStream? = contentResolver.openInputStream(uri)
                        val pathFile = File(context.getExternalFilesDir(null), dirName)
                        if (!pathFile.exists()) {
                            pathFile.mkdirs()
                        }
                        val cache = File(pathFile, fileName)
                        val fos = FileOutputStream(cache)
                        if (inputStream != null) {
                            FileUtils.copy(inputStream, fos)
                        }
                        file = cache
                        fos.close()
                        inputStream?.close()
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                cursor?.close()
            }
        }
        return file?.absolutePath
    }

    /**
     * 获取剩余的存储空间
     */
    private fun getRemainingStorageSpace(): Long {
        runCatching {
            val iPath: File = Environment.getDataDirectory()
            val iStat = StatFs(iPath.path)
            val iBlockSize = iStat.blockSizeLong
            val iAvailableBlocks = iStat.availableBlocksLong
            iAvailableBlocks * iBlockSize
        }.onSuccess {
            return it
        }.onFailure {
            return 0
        }
        return 0
    }
}