package com.all.pdfreader.pro.app.util

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.pdf.PdfRenderer
import android.net.Uri
import android.os.Environment
import android.os.ParcelFileDescriptor
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.util.Log
import com.all.pdfreader.pro.app.PRApp
import com.all.pdfreader.pro.app.R
import com.shockwave.pdfium.PdfiumCore
import java.io.File
import java.io.IOException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.InputStream
import java.security.MessageDigest
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import com.all.pdfreader.pro.app.model.RenameResult
import androidx.core.net.toUri

object FileUtils {

    fun scanPdfFiles(context: Context): List<File> {
        val pdfFiles = mutableListOf<File>()

        // 应用私有目录（无需权限）
        Log.d("ocean", "📁 扫描应用私有目录...")
        scanDirectory(context.filesDir, pdfFiles)
        context.getExternalFilesDir(null)?.let { scanDirectory(it, pdfFiles) }

        // 外部存储根目录（需要权限）
        if (StoragePermissionHelper.hasBasicStoragePermission(context)) {
            Log.d("ocean", "📂 扫描外部存储目录...")
            // 扫描常见的PDF存储目录
            val externalStorage = Environment.getExternalStorageDirectory()
            scanCommonDirectories(externalStorage, pdfFiles)

            // 扫描Download目录
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                ?.let { scanDirectory(it, pdfFiles) }

            // 扫描Documents目录
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
                ?.let { scanDirectory(it, pdfFiles) }

            // 扫描内部存储根目录
            val root = Environment.getExternalStorageDirectory()
            try {
                root.listFiles()?.forEach { dir ->
                    if (dir.isDirectory && !isSystemDirectory(dir)) {
                        val name = dir.name.lowercase()
                        if (name.contains("pdf")) {
                            scanDirectoryRecursive(dir, pdfFiles, 0, 2)
                        }
                    }
                }
            } catch (e: Exception) {
                Log.w("ocean", "⚠️ 无法读取根目录：${root.path}", e)
            }
        }
        val result = pdfFiles.distinct()
        return result
    }

    private fun scanDirectory(directory: File, result: MutableList<File>) {
        if (!directory.exists() || !directory.canRead()) return

        try {
            directory.listFiles()?.forEach { file ->
                when {
                    file.isDirectory -> scanDirectory(file, result)
                    file.isFile && file.extension.equals("pdf", ignoreCase = true) -> {
                        result.add(file)
                        Log.d(
                            "ocean", "   📄 找到PDF: ${file.name} (${formatFileSize(file.length())})"
                        )
                    }
                }
            }
        } catch (e: SecurityException) {
            Log.d("ocean", "⚠️ 跳过目录：${directory.path} (权限不足)")
        }
    }

    private fun scanDirectoryRecursively(directory: File, result: MutableList<File>) {
        if (!directory.exists() || !directory.canRead()) return

        val maxDepth = 3 // 限制递归深度，避免扫描过深
        scanDirectoryRecursive(directory, result, 0, maxDepth)
    }

    private fun scanDirectoryRecursive(
        directory: File, result: MutableList<File>, currentDepth: Int, maxDepth: Int
    ) {
        if (!directory.exists() || !directory.canRead() || currentDepth > maxDepth) return

        try {
            directory.listFiles()?.forEach { file ->
                when {
                    file.isDirectory && !isSystemDirectory(file) -> {
                        scanDirectoryRecursive(file, result, currentDepth + 1, maxDepth)
                    }

                    file.isFile && file.extension.equals("pdf", ignoreCase = true) -> {
                        result.add(file)
                    }
                }
            }
        } catch (e: SecurityException) {
            Log.d("ocean", "⚠️ 跳过目录：${directory.path} (权限不足)")
        }
    }

    private fun scanCommonDirectories(root: File, result: MutableList<File>) {
        val commonDirs = listOf(
            "Download", "Documents", "Books", "PDF", "Ebooks", "阅读", "书籍", "资料"
        )

        commonDirs.forEach { dirName ->
            val dir = File(root, dirName)
            if (dir.exists() && dir.canRead()) {
                Log.d("ocean", "📂 扫描常见目录：${dir.path}")
                scanDirectory(dir, result)
            }
        }
    }

    private fun isSystemDirectory(file: File): Boolean {
        val systemDirs = listOf("Android", ".", "__", "lost+found", "LOST.DIR")
        return systemDirs.any { file.name.startsWith(it, ignoreCase = true) }
    }

    fun scanPdfFilesFromMediaStore(context: Context): List<File> {
        return if (StoragePermissionHelper.hasBasicStoragePermission(context)) {
            scanMediaStoreWithPermission(context)
        } else {
            emptyList()
        }
    }

    private fun scanMediaStoreWithPermission(context: Context): List<File> {
        val pdfFiles = mutableListOf<File>()
        val projection = arrayOf(
            MediaStore.Files.FileColumns.DATA,
            MediaStore.Files.FileColumns.MIME_TYPE,
            MediaStore.Files.FileColumns.DISPLAY_NAME,
            MediaStore.Files.FileColumns.SIZE
        )

        // 更宽松的搜索条件，支持多种PDF MIME类型
        val selection =
            "${MediaStore.Files.FileColumns.MIME_TYPE} IN (?, ?) OR ${MediaStore.Files.FileColumns.DISPLAY_NAME} LIKE ?"
        val selectionArgs = arrayOf(
            "application/pdf", "application/x-pdf", "%.pdf"
        )

        try {
            context.contentResolver.query(
                MediaStore.Files.getContentUri("external"),
                projection,
                selection,
                selectionArgs,
                MediaStore.Files.FileColumns.DATE_MODIFIED + " DESC"
            )?.use { cursor ->
                val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA)

                while (cursor.moveToNext()) {
                    val filePath = cursor.getString(dataColumn)
                    filePath?.let {
                        val file = File(it)
                        if (file.exists() && file.canRead() && isPdfFile(file)) {
                            pdfFiles.add(file)
                            Log.d("ocean", "   📱 MediaStore找到: ${file.name}")
                        }
                    }
                }
            }

            // 额外的文件扩展名搜索（作为MediaStore的补充）
            scanByExtension(pdfFiles)

        } catch (e: SecurityException) {
            Log.d("ocean", "⚠️ MediaStore扫描权限不足")
        } catch (e: Exception) {
            Log.d("ocean", "❌ MediaStore扫描错误: ${e.message}")
        }

        return pdfFiles
    }

    private fun scanByExtension(result: MutableList<File>) {
        // 只扫描自定义目录，避免重复扫描 Downloads/Docs
        val customDirs = listOf(
            File(Environment.getExternalStorageDirectory(), "Books"),
            File(Environment.getExternalStorageDirectory(), "PDF"),
            File(Environment.getExternalStorageDirectory(), "Ebooks")
        )

        val seen = HashSet<String>() // 去重，用绝对路径

        // 先把已有的文件路径加入去重集合
        result.forEach { seen.add(it.absolutePath) }

        customDirs.forEach { dir ->
            if (dir.exists() && dir.canRead()) {
                findPdfFilesByExtension(dir, result, seen)
            }
        }
    }

    private fun findPdfFilesByExtension(directory: File, result: MutableList<File>, seen: HashSet<String>) {
        if (!directory.exists() || !directory.canRead()) return

        try {
            directory.listFiles()?.forEach { file ->
                when {
                    file.isDirectory && !isSystemDirectory(file) -> findPdfFilesByExtension(file, result, seen)

                    file.isFile && file.extension.equals("pdf", ignoreCase = true) -> {
                        if (seen.add(file.absolutePath)) { // HashSet.add 返回 true 表示是新文件
                            result.add(file)
                            Log.d("ocean", "   📂 扫描到: ${file.name}")
                        }
                    }
                }
            }
        } catch (e: SecurityException) {
            Log.d("ocean", "⚠️ 跳过目录：${directory.path}")
        }
    }

    fun getFileInfoFromUri(context: Context, uri: Uri): FileInfo? {
        return try {
            context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
                if (cursor.moveToFirst()) {
                    val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                    val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)

                    val name = if (nameIndex != -1) cursor.getString(nameIndex) else ""
                    val size =
                        if (sizeIndex != -1 && !cursor.isNull(sizeIndex)) cursor.getLong(sizeIndex) else 0L

                    FileInfo(
                        name = name, size = size, uri = uri
                    )
                } else null
            }
        } catch (e: Exception) {
            null
        }
    }

    /**
     * 计算文件哈希
     */
    fun calculateFileHash(filePath: String): String? {
        return try {
            val file = File(filePath)
            if (!file.exists() || !file.canRead()) return null

            calculateHash(file.inputStream())
        } catch (e: Exception) {
            null
        }
    }

    fun calculateFileHash(uri: Uri, context: Context): String? {
        return try {
            context.contentResolver.openInputStream(uri)?.use { inputStream ->
                calculateHash(inputStream)
            }
        } catch (e: Exception) {
            null
        }
    }

    private fun calculateHash(inputStream: InputStream): String {
        val digest = MessageDigest.getInstance("MD5")
        val buffer = ByteArray(8192)
        var bytes = inputStream.read(buffer)

        while (bytes >= 0) {
            digest.update(buffer, 0, bytes)
            bytes = inputStream.read(buffer)
        }

        return digest.digest().joinToString("") { "%02x".format(it) }
    }

    fun isPdfFile(file: File): Boolean {
        return file.exists() && file.isFile && file.extension.equals(
            "pdf", ignoreCase = true
        ) && file.length() > 0
    }

    fun getFileExtension(fileName: String): String {
        return fileName.substringAfterLast('.', "")
    }

    private const val kb = 1024.0
    private const val mb = kb * 1024
    private const val gb = mb * 1024

    @SuppressLint("DefaultLocale")
    fun formatFileSize(size: Long): String {
        return when {
            size <= 0 -> "0 B"
            size < kb -> "$size B"
            size < mb -> String.format("%.2f KB", size / kb)
            size < gb -> String.format("%.2f MB", size / mb)
            else -> String.format("%.2f GB", size / gb)
        }
    }

    @SuppressLint("DefaultLocale")
    fun Long.toFormatFileSize(): String {
        val size = this.toDouble()
        return when {
            size <= 0 -> "0 B"
            size < kb -> "$size B"
            size < mb -> String.format("%.2f KB", size / kb)
            size < gb -> String.format("%.2f MB", size / mb)
            else -> String.format("%.2f GB", size / gb)
        }
    }

    fun Long.toSlashDate(): String {
        val sdf = SimpleDateFormat("M/d/yyyy", Locale.ENGLISH)
        return sdf.format(Date(this))
    }

    fun Long.toSlashDateTime(): String {
        val sdf = SimpleDateFormat("M/d/yyyy HH:mm", Locale.ENGLISH)
        return sdf.format(Date(this))
    }

    fun Long.toUnderscoreDateTime(): String {
        val sdf = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH)
        return sdf.format(Date(this))
    }

    data class FileInfo(
        val name: String, val size: Long, val uri: Uri
    )

    /**
     * 判断 PDF 是否加密（基于原生 PdfRenderer）
     *
     * @param file 要检测的 PDF 文件
     * @return true = 已加密 / 不能打开，false = 未加密
     */
    fun isPdfEncrypted(file: File): Boolean {
        var fd: ParcelFileDescriptor? = null
        var renderer: PdfRenderer? = null
        return try {
            fd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
            renderer = PdfRenderer(fd)
            // 能成功打开 => 没有加密
            false
        } catch (e: SecurityException) {
            // PdfRenderer 在遇到加密 PDF 时可能抛 SecurityException
            true
        } catch (e: IOException) {
            // 某些加密 PDF 也可能走 IOException
            e.message?.contains("password", ignoreCase = true) == true
        } finally {
            try {
                renderer?.close()
                fd?.close()
            } catch (_: Exception) {
            }
        }
    }

    /**
     * 判断pdf密码是否正确
     */
    fun isPdfPasswordCorrect(context: Context, file: File, password: String): Boolean {
        return try {
            ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY).use { descriptor ->
                val pdfiumCore = PdfiumCore(context)
                val doc = pdfiumCore.newDocument(descriptor, password)
                pdfiumCore.closeDocument(doc)
            }
            true// 没抛异常说明密码正确
        } catch (e: Exception) {
            false // 抛异常说明密码错误
        }
    }

    /**
     * 重命名文件（同步版本）- 智能处理后缀
     *
     * @param file 要重命名的文件
     * @param newName 新文件名（可包含或不包含后缀，会自动处理）
     * @return RenameResult对象，包含成功状态和错误信息
     */
    fun renameFile(file: File, newName: String): RenameResult {
        if (!file.exists()) {
            return RenameResult.failure(PRApp.getStringRes(R.string.error_file_not_exist))
        }

        if (!file.canWrite()) {
            return RenameResult.failure(PRApp.getStringRes(R.string.error_no_write_permission))
        }

        // 智能处理后缀：如果用户没有提供后缀，保留原文件后缀
        val finalName = if (newName.contains('.')) {
            // 用户提供了后缀，使用用户的
            newName
        } else {
            // 用户没有提供后缀，自动添加原文件后缀
            val originalExtension = file.extension
            if (originalExtension.isNotEmpty()) {
                "$newName.$originalExtension"
            } else {
                newName
            }
        }

        // 验证新文件名
        val validatedName = validateFileName(finalName) ?: run {
            return RenameResult.failure(PRApp.getStringRes(R.string.error_invalid_file_name))
        }

        // 获取原文件的父目录
        val parentDir = file.parentFile ?: run {
            return RenameResult.failure(PRApp.getStringRes(R.string.error_no_parent_directory))
        }

        // 构建新文件对象
        val newFile = File(parentDir, validatedName)

        // 检查目标文件是否已存在
        if (newFile.exists()) {
            return RenameResult.failure(PRApp.getStringRes(R.string.error_target_file_exists))
        }

        return try {
            if (file.renameTo(newFile)) {
                Log.d("ocean", "✅ File renamed successfully: ${file.name} -> $validatedName")
                RenameResult.success(newName)
            } else {
                Log.e("ocean", "❌ File rename failed: ${file.path}")
                RenameResult.failure(PRApp.getStringRes(R.string.error_file_rename_failed))
            }
        } catch (e: SecurityException) {
            RenameResult.failure(PRApp.getStringRes(R.string.error_insufficient_permission))
        } catch (e: Exception) {
            Log.e("ocean", "❌ File rename exception: ${e.message}")
            RenameResult.failure(
                PRApp.getStringRes(
                    R.string.error_file_rename_exception, e.message.toString()
                )
            )
        }
    }

    /**
     * 重命名文件（异步版本）
     *
     * @param file 要重命名的文件
     * @param newName 新文件名（可包含或不包含后缀，会自动处理）
     * @return RenameResult对象，包含成功状态和错误信息
     */
    suspend fun renameFileAsync(file: File, newName: String): RenameResult =
        withContext(Dispatchers.IO) {
            renameFile(file, newName)
        }

    /**
     * 移除文件扩展名（后缀）
     *
     * @param fileName 原始文件名
     * @return 不包含扩展名的文件名
     */
    fun removeFileExtension(fileName: String): String {
        val lastDotIndex = fileName.lastIndexOf('.')
        return if (lastDotIndex > 0 && lastDotIndex < fileName.length - 1) {
            // 确保点号不在开头，且后面还有字符
            fileName.substring(0, lastDotIndex)
        } else {
            // 没有扩展名，或者点号在开头（如.hidden文件）
            fileName
        }
    }

    /**
     * 验证并清理文件名
     *
     * @param fileName 原始文件名
     * @return 验证通过的文件名，如果无效则返回null
     */
    fun validateFileName(fileName: String): String? {
        if (fileName.isBlank()) return null

        // 移除文件系统中的非法字符
        val cleanedName = fileName.replace(Regex("[<>:\"|?*\u0000-\u001f]"), "_")
            .replace(Regex("^\\.+"), "") // 移除开头的点
            .trim()

        if (cleanedName.isEmpty() || cleanedName == "." || cleanedName == "..") {
            return "NewFile"
        }

        // 确保文件名长度合理（通常文件系统支持255字符）
        if (cleanedName.length > 255) {
            return cleanedName.substring(0, 255)
        }

        return cleanedName
    }

    fun getFileFromUri(context: Context, uri: Uri): File? {
        // 先尝试通过 DATA 字段获取
        val projection = arrayOf(MediaStore.Files.FileColumns.DATA)
        context.contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
            if (cursor.moveToFirst()) {
                val path =
                    cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA))
                if (!path.isNullOrEmpty()) {
                    val file = File(path)
                    if (file.exists()) {
                        return file
                    }
                }
            }
        }

        // Android 10+ 或 DATA 字段为空时，使用 ContentResolver 流访问
        return try {
            val tempFile = File(context.cacheDir, "temp_pdf_${System.currentTimeMillis()}.pdf")
            context.contentResolver.openInputStream(uri)?.use { input ->
                tempFile.outputStream().use { output ->
                    input.copyTo(output)
                }
            }
            tempFile
        } catch (e: Exception) {
//            Log.e("ocean", "无法获取文件: ${e.message}", e)
            null
        }
    }

    fun duplicateFile(originalFile: File): File? {
        if (!originalFile.exists()) return null

        val parentDir = originalFile.parentFile ?: return null
        val fileName = originalFile.nameWithoutExtension
        val extension = originalFile.extension

        // 自动生成不重复的新文件名
        var newFile = File(parentDir, "$fileName (copy).$extension")
        var index = 1
        while (newFile.exists()) {
            newFile = File(parentDir, "$fileName ($index).$extension")
            index++
        }

        // 执行复制
        originalFile.inputStream().use { input ->
            newFile.outputStream().use { output ->
                input.copyTo(output)
            }
        }

        return newFile
    }


    fun uriToFile(context: Context, path: String): File? {
        return try {
            if (path.startsWith("content://")) {
                // 是 content:// Uri，需要拷贝到临时文件
                val uri = path.toUri()
                val inputStream = context.contentResolver.openInputStream(uri) ?: return null
                val tempFile = File(context.cacheDir, "temp_${System.currentTimeMillis()}.jpg")
                tempFile.outputStream().use { output ->
                    inputStream.copyTo(output)
                }
                inputStream.close()
                tempFile
            } else {
                // 是普通文件路径
                val file = File(path)
                if (file.exists()) file else null
            }
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    fun getParentFolderName(path: String): String? {
        val file = File(path)
        return file.parentFile?.name
    }
}