package mg.dot.feufaro

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Environment
import android.widget.Toast
import androidx.core.content.FileProvider
import feufaro.composeapp.generated.resources.Res
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
import java.net.URLDecoder
import java.nio.charset.StandardCharsets

class AndroidFileRepository(private val context: Context) : FileRepository {

    override suspend fun getOutputStream(filePath: String): OutputStream {
        // On utilise getExternalFilesDir pour le debug (accessible via ADB/Vim)
        val folder = context.getExternalFilesDir(null)
        val outputFile = File(folder, filePath)

        // On s'assure que le dossier existe
        outputFile.parentFile?.mkdirs()

        return FileOutputStream(outputFile)
    }

    override suspend fun saveFile(filePath: String, data: ByteArray) {
        val folder = context.getExternalFilesDir(null)
        println("Save to xx27 $folder $filePath")
        File(folder, filePath).writeBytes(data)
    }
    override suspend fun readFileLines(filePath: String): List<String> = withContext(Dispatchers.IO) {
        try {
            when {
                filePath.startsWith("content://") -> {
                    val uri = Uri.parse(filePath)
                    val inputStream = context.contentResolver.openInputStream(uri)
                        ?: throw IOException("Impossible d'ouvrir : $filePath")
                    inputStream.bufferedReader(Charsets.UTF_8).readLines()
                }
                filePath.startsWith("assets://") -> {
                    readAssetFileLines(filePath)
                }

                else -> {
                    val file = File(filePath)
                    println("AndroidRead: Tentative sur ${file.absolutePath}")
                    println("AndroidRead: Existe=${file.exists()} | Lisible=${file.canRead()}")

                    if (!file.exists()) {
                        throw IOException("Le fichier n'existe pas : $filePath")
                    }
                    file.bufferedReader(Charsets.UTF_8).useLines { it.toList() }
                }
            }
        } catch (e: IOException) {
            throw IOException("Failed to read file or asset '$filePath'")
        }
    }
    override suspend fun readFileContent(filePath: String): String = withContext(Dispatchers.IO) {
        val lines = readFileLines(filePath)
        lines.joinToString("\n") { it }
    }
    private suspend fun readAssetFileLines(assetFileName: String): List<String> {
        return try {
            Res.readBytes("files/"+assetFileName.removePrefix("assets://")).decodeToString().split("\n")
        } catch (e: IOException) {
            println("Could not read /"+assetFileName.removePrefix("assets://"))
            throw IOException("Could not read asset file: $assetFileName", e)
        }
    }

    /* Exwternal files */
    override fun getFileName(shortName: String): String {
        val folder = context.getExternalFilesDir(null)
        return "$folder/$shortName"
    }

    private fun String.parseSafToRelativePath(): String {
        if (!this.startsWith("content://")) return this

        return try {
            val decodedUri = URLDecoder.decode(this, StandardCharsets.UTF_8.name())
            val documentPath = decodedUri.substringAfter("/document/", decodedUri)

            when {
                documentPath.startsWith("home:") -> "Documents/" + documentPath.substringAfter("home:")
                documentPath.startsWith("primary:") -> documentPath.substringAfter("primary:")
                documentPath.contains(":") -> documentPath.substringAfter(":")
                else -> documentPath
            }
        } catch (e: Exception) {
            this
        }
    }

    override suspend fun saveLocalFile(filePath: String, data: ByteArray) = withContext(Dispatchers.IO) {
        try {
            if (filePath.startsWith("content://") || filePath.startsWith("file://")) {
                val uri = Uri.parse(filePath)
                context.contentResolver.openOutputStream(uri, "rwt")?.use { outputStream ->
                    outputStream.write(data)
                    outputStream.flush()
                } ?: throw Exception("Impossible d'ouvrir l'Uri pour écriture")
            } else {
                val file = if (filePath.contains("/")) {
                    File(filePath)
                } else {
                    File(getAppPublicFolder(), filePath)
                }
                file.parentFile?.mkdirs()
                file.writeBytes(data)
            }

            val displayPath = filePath.parseSafToRelativePath()

            withContext(Dispatchers.Main) {
                if (filePath.endsWith(".pdf", ignoreCase = true)) {
                    openPdfFile(context = context, filePath = filePath)
                } else {
                    val shortDisplayPath = longPathToShort(displayPath)

                    val message = if (shortDisplayPath.endsWith(".json", ignoreCase = true)) {
                        "Playlist mise à jour"
                    } else {
                        "Sauvegarde réussie dans : $shortDisplayPath"
                    }
                    Toast.makeText(
                        context.applicationContext,
                        message,
                        Toast.LENGTH_LONG
                    ).show()
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            withContext(Dispatchers.Main) {
                Toast.makeText(context, "Erreur de sauvegarde : ${e.message}", Toast.LENGTH_SHORT).show()
            }
            throw e
        }
    }

    private fun longPathToShort(displayPath: String): String {
        return if (displayPath.contains("Documents/")) {
            "Documents/" + displayPath.substringAfter("Documents/")
        } else {
            displayPath.substringAfterLast('/')
        }
    }

    override suspend fun getAppPublicFolder(): File {
        val publicDocsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
        val appDir = File(publicDocsDir, "Feufaro")
        if (!appDir.exists()) {
            appDir.mkdirs()
        }
        return appDir
    }
    private fun getPAppPublicFolder(): File {
        val publicDocsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
        val appDir = File(publicDocsDir, "Feufaro")
        if (!appDir.exists()) {
            appDir.mkdirs()
        }
        return appDir
    }

    override fun pickSavePath(defaultName: String, title: String): String? {
        val publicFolder = getPAppPublicFolder()
        val file = File(publicFolder, defaultName)
        return file?.absolutePath
    }
    suspend fun openPdfFile(context: Context, filePath: String) {
        val file = File(filePath)
        if (!file.exists()) return

        // 1. Transformer le File en Uri sécurisée
        val uri: Uri = FileProvider.getUriForFile(
            context,
            "mg.dot.feufaro.fileprovider",
            file
        )

        val intent = Intent(Intent.ACTION_VIEW).apply {
            setDataAndType(uri, "application/pdf")
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }

        val sPath = longPathToShort(filePath)
        try {
            withContext(Dispatchers.Main) {
                Toast.makeText(context.applicationContext, "Fichier sauvegardé avec succès dans $sPath", Toast.LENGTH_LONG).show()
            }
            context.startActivity(intent)
        } catch (e: Exception) {
            withContext(Dispatchers.Main) {
                Toast.makeText(context.applicationContext, "Aucun lecteur PDF trouvé", Toast.LENGTH_SHORT).show()
            }
        }
    }
}