package com.base.appzxhy.utils

import android.annotation.SuppressLint
import android.content.Context
import android.database.Cursor
import android.media.MediaScannerConnection
import android.net.Uri
import android.provider.MediaStore
import com.base.appzxhy.bean.FileBean
import java.text.SimpleDateFormat
import java.util.Locale

object MediaUtils {

    private val projection = arrayOf(
        MediaStore.Files.FileColumns.DISPLAY_NAME,
        MediaStore.Files.FileColumns.DATA,
        MediaStore.Files.FileColumns.SIZE,
        MediaStore.Files.FileColumns.DATE_MODIFIED,
        MediaStore.Files.FileColumns.MIME_TYPE
    )

    private const val EXTERNAL = "external"

    fun updateMedia(context: Context, paths: Array<String>) {
        if (paths.isEmpty()) return
        MediaScannerConnection.scanFile(context, paths, null, null)
    }

    fun findFiles(context: Context, size: Long = 0): MutableList<FileBean> {
        return queryFilesWithSize(context, MediaStore.Files.getContentUri(EXTERNAL), size)
    }

    fun findSpecifiedFiles(context: Context): MutableList<FileBean> {
        val suffixes = arrayOf("%.log", "%.apk", "%.aab", "%.temp", "%.LOG", "%.APK", "%.AAB", "%.TEMP")
        return queryFilesWithSuffixes(context, MediaStore.Files.getContentUri(EXTERNAL), suffixes)
    }

    fun findScreenshotsFiles(context: Context, block: (total: Long, MutableList<FileBean>) -> Unit) {
        val selection = "${MediaStore.Images.Media.RELATIVE_PATH} LIKE ?"
        val selectionArgs = arrayOf("%Screenshots%")
        val list = query(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs)
        val map = mutableMapOf<String, MutableList<FileBean>>()
        val dateFormat = SimpleDateFormat("yyyy/MM", Locale.getDefault())
        list.forEach { map.getOrPut(dateFormat.format(it.lastModified)) { mutableListOf() }.add(it) }
        val result = mutableListOf<FileBean>()
        map.forEach { (key, value) ->
            result.add(FileBean(key, items = value))
        }
        block(list.sumOf { it.length }, result)
    }

    fun findImageFiles(context: Context, size: Long = 0): MutableList<FileBean> {
        return queryFilesWithSize(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, size)
    }

    fun findVideoFiles(context: Context, size: Long = 0): MutableList<FileBean> {
        return queryFilesWithSize(context, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, size)
    }

    fun findAudioFiles(context: Context, size: Long = 0): MutableList<FileBean> {
        return queryFilesWithSize(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, size)
    }

    fun findDocFiles(context: Context, size: Long = 0): MutableList<FileBean> {
        val mimeTypes = arrayOf(
            "text/plain",
            "application/msword",
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/vnd.ms-excel",
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "application/pdf",
        )
        return queryFilesWithMimeTypes(context, MediaStore.Files.getContentUri(EXTERNAL), mimeTypes, size)
    }

    private fun queryFilesWithSuffixes(context: Context, uri: Uri, suffixes: Array<String>): MutableList<FileBean> {
        val selection = suffixes.joinToString(separator = " OR ") { "${MediaStore.Files.FileColumns.DISPLAY_NAME} LIKE ?" }
        return query(context, uri, projection, selection, suffixes)
    }

    private fun queryFilesWithSize(context: Context, uri: Uri, size: Long): MutableList<FileBean> {
        var selection: String? = null
        var selectionArgs: Array<String>? = null
        if (size > 0) {
            selection = "${MediaStore.Files.FileColumns.SIZE} >= ?"
            selectionArgs = arrayOf(size.toString())
        }
        return query(context, uri, projection, selection, selectionArgs)
    }

    private fun queryFilesWithMimeTypes(context: Context, uri: Uri, mimeTypes: Array<String>, size: Long): MutableList<FileBean> {
        val (selection, selectionArgs) = buildSelectionWithMimeTypes(mimeTypes, size)
        return query(context, uri, projection, selection, selectionArgs)
    }

    private fun buildSelectionWithMimeTypes(mimeTypes: Array<String>, size: Long): Pair<String, Array<String>> {
        val mimeTypeConditions = mimeTypes.joinToString(separator = " OR ") { "${MediaStore.Files.FileColumns.MIME_TYPE}=?" }
        val sizeCondition = "${MediaStore.Files.FileColumns.SIZE} >=?"
        val selection = "($mimeTypeConditions) AND ($sizeCondition)"
        val selectionArgs = mimeTypes + size.toString()
        return selection to selectionArgs
    }

    private fun buildSelectionWithMimeTypes(mimeTypes: Array<String>): Pair<String, Array<String>> {
        val selection = mimeTypes.joinToString(prefix = "${MediaStore.Files.FileColumns.MIME_TYPE}=?", separator = " OR ") { "'$it'" }
        val selectionArgs = mimeTypes
        return Pair(selection, selectionArgs)
    }

    @SuppressLint("Range")
    private fun query(
        context: Context,
        uri: Uri,
        projection: Array<String>,
        selection: String? = null,
        selectionArgs: Array<String>? = null,
        sortOrder: String = MediaStore.Files.FileColumns.DATE_MODIFIED
    ): MutableList<FileBean> {
        val list = mutableListOf<FileBean>()
        var cursor: Cursor? = null
        try {
            val contentResolver = context.contentResolver
            cursor = contentResolver.query(
                uri,
                projection,
                selection,
                selectionArgs,
                "$sortOrder DESC"
            )
            cursor?.let {
                while (it.moveToNext()) {
                    val displayName = it.getString(it.getColumnIndex(projection[0]))
                    val filePath = it.getString(it.getColumnIndex(projection[1]))
                    val size = it.getLong(it.getColumnIndex(projection[2]))
                    val dateModified = it.getLong(it.getColumnIndex(projection[3])) * 1000
                    val mineType = it.getString(it.getColumnIndex(projection[4]))
                    list.add(FileBean(displayName, filePath, 0, size, dateModified, mineType))
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            cursor?.close()
        }
        return list
    }
}