package com.cheng.blzb.utils

import android.content.ContentResolver
import android.content.ContentValues
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import androidx.annotation.RequiresApi
import com.example.base.utils.AppUtils
import com.example.base.utils.L
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
import java.nio.file.Files


object SaveUtils {
    private const val TAG = "SaveUtils"

    /**
     * 将图片文件保存到系统相册
     */
    fun saveImgFileToAlbum(context: Context, imageFilePath: String, record: Boolean = true): Boolean {
        Log.d(TAG, "saveImgToAlbum() imageFile = [$imageFilePath]")
        return try {
            val bitmap = BitmapFactory.decodeFile(imageFilePath)
            saveBitmapToAlbum(context, bitmap, record)
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    /**
     * 将bitmap保存到系统相册
     */
    fun saveBitmapToAlbum(context: Context, bitmap: Bitmap?, record: Boolean = true): Boolean {
        if (bitmap == null) return false
        val fileName = "jk_${System.currentTimeMillis()}.jpeg"
        val saved =  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            saveBitmapToAlbumBeforeQ(context, bitmap, fileName)
        } else {
            saveBitmapToAlbumAfterQ(context, bitmap, fileName)
        }
        return saved
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    private fun saveBitmapToAlbumAfterQ(context: Context, bitmap: Bitmap, fileName: String): Boolean {
        val contentUri: Uri = if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        } else {
            MediaStore.Images.Media.INTERNAL_CONTENT_URI
        }
        val contentValues = getImageContentValues(fileName)
        val uri = context.contentResolver.insert(contentUri, contentValues) ?: return false
        var os: OutputStream? = null
        return try {
            os = context.contentResolver.openOutputStream(uri)
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os!!)
            contentValues.clear()
            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
            context.contentResolver.update(uri, contentValues, null, null)
            true
        } catch (e: Exception) {
            context.contentResolver.delete(uri, null, null)
            e.printStackTrace()
            false
        } finally {
            try {
                os?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    private fun saveBitmapToAlbumBeforeQ(context: Context, bitmap: Bitmap, fileName: String): Boolean {
        val picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
        val destDir = File(picDir, AppUtils.getAppName())
        if (!destDir.exists() || !destDir.isDirectory) destDir.mkdirs()
        val destFile = File(destDir, fileName)
        var os: OutputStream? = null
        var result = false
        try {
            os = BufferedOutputStream(FileOutputStream(destFile))
            result = bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os)
            if (!bitmap.isRecycled) bitmap.recycle()
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            try {
                os?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        MediaScannerConnection.scanFile(context, arrayOf<String>(destFile.absolutePath), arrayOf("image/*")) { path: String, uri: Uri ->
            Log.d(TAG, "saveImgToAlbum: $path $uri")
        }
        return result
    }

    /**
     * 获取图片的ContentValue
     *
     * @param context
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private fun getImageContentValues(fileName: String): ContentValues {
        val contentValues = ContentValues()
        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
        contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + File.separator + AppUtils.getAppName())
        contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1)
        contentValues.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
        contentValues.put(MediaStore.Images.Media.DATE_MODIFIED, System.currentTimeMillis())
        contentValues.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
        return contentValues
    }

    /**
     * 将视频保存到系统相册
     */
    fun saveVideoToAlbum(context: Context, videoFile: String): Boolean {
        Log.d(TAG, "saveVideoToAlbum() videoFile = [$videoFile]")
        val saved =  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            saveVideoToAlbumBeforeQ(context, videoFile)
        } else {
            saveVideoToAlbumAfterQ(context, videoFile)
        }
        return saved
    }

    private fun saveVideoToAlbumAfterQ(context: Context, videoFile: String): Boolean {
        return try {
            val contentResolver = context.contentResolver
            val tempFile = File(videoFile)
            val contentValues = getVideoContentValues(tempFile, System.currentTimeMillis())
            val uri = contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues)
            copyFileAfterQ(context, contentResolver, tempFile, uri)
            contentValues.clear()
            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
            context.contentResolver.update(uri!!, contentValues, null, null)
            true
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    private fun saveVideoToAlbumBeforeQ(context: Context, videoFile: String): Boolean {
        val picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
        val tempFile = File(videoFile)
        val destDir = File(picDir, AppUtils.getAppName())
        if (!destDir.exists() || !destDir.isDirectory) destDir.mkdirs()
        val destFile = File(destDir, tempFile.getName())
        var ins: FileInputStream? = null
        var ous: BufferedOutputStream? = null
        return try {
            ins = FileInputStream(tempFile)
            ous = BufferedOutputStream(FileOutputStream(destFile))
            var nread = 0L
            val buf = ByteArray(1024)
            var n: Int
            while (ins.read(buf).also { n = it } > 0) {
                ous.write(buf, 0, n)
                nread += n.toLong()
            }
            MediaScannerConnection.scanFile(
                context, arrayOf<String>(destFile.absolutePath), arrayOf("video/*")
            ) { path: String, uri: Uri ->
                L.d("saveVideoToAlbum: $path $uri")
            }
            true
        } catch (e: Exception) {
            e.printStackTrace()
            false
        } finally {
            try {
                ins?.close()
                ous?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    @Throws(IOException::class)
    private fun copyFileAfterQ(context: Context, localContentResolver: ContentResolver, tempFile: File, localUri: Uri?) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
            context.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q
        ) {
            //拷贝文件到相册的uri,android10及以上得这么干，否则不会显示。可以参考ScreenMediaRecorder的save方法
            val os = localContentResolver.openOutputStream(localUri!!)
            Files.copy(tempFile.toPath(), os)
            os!!.close()
        }
    }

    /**
     * 获取视频的contentValue
     */
    private fun getVideoContentValues(paramFile: File, timestamp: Long): ContentValues {
        val localContentValues = ContentValues()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            localContentValues.put(
                MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM
                        + File.separator + AppUtils.getAppName()
            )
        }
        localContentValues.put(MediaStore.Video.Media.TITLE, paramFile.getName())
        localContentValues.put(MediaStore.Video.Media.DISPLAY_NAME, paramFile.getName())
        localContentValues.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
        localContentValues.put(MediaStore.Video.Media.DATE_TAKEN, timestamp)
        localContentValues.put(MediaStore.Video.Media.DATE_MODIFIED, timestamp)
        localContentValues.put(MediaStore.Video.Media.DATE_ADDED, timestamp)
        localContentValues.put(MediaStore.Video.Media.SIZE, paramFile.length())
        return localContentValues
    }

    /**
     * 将视频音频到系统
     */
    fun saveAudioToAlbum(context: Context, audioFile: String): Boolean {
        Log.d(TAG, "saveAudioToAlbum() audioFile = [$audioFile]")
        val saved =  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            saveAudioToAlbumBeforeQ(context, audioFile)
        } else {
            saveAudioToAlbumAfterQ(context, audioFile)
        }
        return saved
    }

    private fun saveAudioToAlbumAfterQ(context: Context, audioFile: String): Boolean {
        return try {
            val contentResolver = context.contentResolver
            val tempFile = File(audioFile)
            val contentValues = getAudioContentValues(tempFile, System.currentTimeMillis())
            val uri = contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues)
            copyFileAfterQ(context, contentResolver, tempFile, uri)
            contentValues.clear()
            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
            context.contentResolver.update(uri!!, contentValues, null, null)
            true
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    private fun saveAudioToAlbumBeforeQ(context: Context, audioFile: String): Boolean {
        val picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)
        val tempFile = File(audioFile)
        val destDir = File(picDir, AppUtils.getAppName())
        if (!destDir.exists() || !destDir.isDirectory) destDir.mkdirs()
        val destFile = File(destDir, tempFile.getName())
        var ins: FileInputStream? = null
        var ous: BufferedOutputStream? = null
        return try {
            ins = FileInputStream(tempFile)
            ous = BufferedOutputStream(FileOutputStream(destFile))
            var nread = 0L
            val buf = ByteArray(1024)
            var n: Int
            while (ins.read(buf).also { n = it } > 0) {
                ous.write(buf, 0, n)
                nread += n.toLong()
            }
            MediaScannerConnection.scanFile(
                context, arrayOf<String>(destFile.absolutePath), arrayOf("audio/*")
            ) { path: String, uri: Uri ->
                L.d("saveAudioToAlbum: $path $uri")
            }
            true
        } catch (e: Exception) {
            e.printStackTrace()
            false
        } finally {
            try {
                ins?.close()
                ous?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    /**
     * 获取音频的contentValue
     */
    private fun getAudioContentValues(paramFile: File, timestamp: Long): ContentValues {
        val localContentValues = ContentValues()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            localContentValues.put(
                MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC
                        + File.separator + AppUtils.getAppName()
            )
        }
        localContentValues.put(MediaStore.Audio.Media.TITLE, paramFile.getName())
        localContentValues.put(MediaStore.Audio.Media.DISPLAY_NAME, paramFile.getName())
        localContentValues.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mp3")
        localContentValues.put(MediaStore.Audio.Media.DATE_TAKEN, timestamp)
        localContentValues.put(MediaStore.Audio.Media.DATE_MODIFIED, timestamp)
        localContentValues.put(MediaStore.Audio.Media.DATE_ADDED, timestamp)
        localContentValues.put(MediaStore.Audio.Media.SIZE, paramFile.length())
        return localContentValues
    }
}