package com.tsmobile.app.data

import android.content.Context
import android.util.Base64
import android.util.Log
import com.tsmobile.app.TSBridge
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import java.io.File
import java.net.HttpURLConnection
import java.net.URL

/**
 * 文件下载管理器。
 * 负责从 TeamSpeak 服务器下载文件并缓存到本地。
 *
 * 下载流程：TSBridge.downloadFileBytes → base64 解码 → 写入缓存目录。
 * 缓存策略：按 file_id 命名，永久缓存（由调用方管理失效）。
 */
object FileDownloadManager {

    private const val TAG = "FileDownloadManager"
    private const val CACHE_DIR = "ts_file_cache"

    // 防止同一文件并发下载
    private val downloadMutex = Mutex()
    private val downloading = mutableSetOf<String>()

    private val json = Json { ignoreUnknownKeys = true }

    /**
     * 获取文件的本地缓存路径。
     * 如果文件已缓存，返回 File 对象；否则返回 null。
     */
    fun getCachedFile(context: Context, fileId: String): File? {
        val file = getCacheFile(context, fileId)
        return if (file.exists() && file.length() > 0) file else null
    }

    /**
     * 下载文件并缓存到本地。
     * 尝试多种路径格式来找到文件。
     *
     * @param context Android Context
     * @param channelID 当前频道 ID
     * @param fileId 文件 ID（base64 编码）
     * @param fileName 文件名（如 "image.jpg"）
     * @return 缓存文件的 File 对象，失败返回 null
     */
    suspend fun downloadAndCache(
        context: Context,
        channelID: String,
        fileId: String,
        fileName: String
    ): File? = withContext(Dispatchers.IO) {
        // 先检查缓存
        getCachedFile(context, fileId)?.let { return@withContext it }

        // 防止同一文件并发下载
        downloadMutex.withLock {
            // 双重检查
            getCachedFile(context, fileId)?.let { return@withContext it }

            if (fileId in downloading) {
                Log.d(TAG, "Already downloading: $fileId")
                return@withContext null
            }
            downloading.add(fileId)
        }

        try {
            Log.d(TAG, "Downloading file: $fileName (channel=$channelID, fileId=$fileId)")

            // 尝试多种路径格式
            val decodedFileId = try {
                String(Base64.decode(fileId, Base64.DEFAULT))
            } catch (_: Exception) {
                fileId
            }

            val pathVariants = listOf(
                "/$fileId",           // 原始 file_id
                "/$decodedFileId",    // base64 解码后的 file_id
                "/$fileName",         // 文件名
            )

            for (path in pathVariants) {
                Log.d(TAG, "Trying path: $path")
                val result = TSBridge.downloadFileBytes(channelID, path)
                if (result == "{}" || result.isEmpty()) {
                    continue
                }

                // 解析 JSON 响应
                val response = json.decodeFromString<kotlinx.serialization.json.JsonObject>(result)
                val data = response["data"]?.toString()?.trim('"') ?: continue

                // base64 解码
                val bytes = Base64.decode(data, Base64.DEFAULT)
                if (bytes.isEmpty()) {
                    continue
                }

                // 写入缓存
                val cacheFile = getCacheFile(context, fileId)
                cacheFile.parentFile?.mkdirs()
                cacheFile.writeBytes(bytes)
                Log.d(TAG, "File cached: ${cacheFile.absolutePath} (${bytes.size} bytes)")

                return@withContext cacheFile
            }

            Log.w(TAG, "All download attempts failed for: $fileName")
            return@withContext null
        } catch (e: Exception) {
            Log.e(TAG, "Download error for $fileName", e)
            return@withContext null
        } finally {
            downloadMutex.withLock {
                downloading.remove(fileId)
            }
        }
    }

    /**
     * 下载 MyTS 文件并缓存到本地。
     * MyTS 文件存储在独立服务器（chat-3.tmspk.net），需要通过 HTTP 下载。
     *
     * @param context Android Context
     * @param fileId 文件 ID（base64 编码）
     * @param fileName 文件名
     * @param chatUserId MyTS 聊天用户 ID（格式：@userId:serverHost）
     * @return 缓存文件的 File 对象，失败返回 null
     */
    suspend fun downloadMyTSFile(
        context: Context,
        fileId: String,
        fileName: String,
        chatUserId: String
    ): File? = withContext(Dispatchers.IO) {
        // 先检查缓存
        getCachedFile(context, fileId)?.let { return@withContext it }

        // 解析 chat_user_id 获取服务器地址
        val serverHost = parseMyTSServerHost(chatUserId)
        if (serverHost.isEmpty()) {
            Log.w(TAG, "Failed to parse MyTS server host from: $chatUserId")
            return@withContext null
        }

        // 防止同一文件并发下载
        downloadMutex.withLock {
            // 双重检查
            getCachedFile(context, fileId)?.let { return@withContext it }

            if (fileId in downloading) {
                Log.d(TAG, "Already downloading: $fileId")
                return@withContext null
            }
            downloading.add(fileId)
        }

        try {
            Log.d(TAG, "Downloading MyTS file: $fileName (server=$serverHost, fileId=$fileId)")

            // 尝试多种 URL 格式
            val decodedFileId = try {
                String(Base64.decode(fileId, Base64.DEFAULT))
            } catch (_: Exception) {
                fileId
            }

            val urlVariants = listOf(
                "https://$serverHost/files/$fileId",
                "https://$serverHost/files/$decodedFileId",
                "https://$serverHost/$fileId",
                "https://$serverHost/$decodedFileId",
            )

            for (urlStr in urlVariants) {
                Log.d(TAG, "Trying URL: $urlStr")
                try {
                    val url = URL(urlStr)
                    val conn = url.openConnection() as HttpURLConnection
                    conn.connectTimeout = 10000
                    conn.readTimeout = 30000
                    conn.requestMethod = "GET"

                    if (conn.responseCode == 200) {
                        val bytes = conn.inputStream.readBytes()
                        if (bytes.isNotEmpty()) {
                            // 写入缓存
                            val cacheFile = getCacheFile(context, fileId)
                            cacheFile.parentFile?.mkdirs()
                            cacheFile.writeBytes(bytes)
                            Log.d(TAG, "MyTS file cached: ${cacheFile.absolutePath} (${bytes.size} bytes)")
                            return@withContext cacheFile
                        }
                    }
                    conn.disconnect()
                } catch (e: Exception) {
                    Log.d(TAG, "HTTP request failed for $urlStr: ${e.message}")
                }
            }

            Log.w(TAG, "All MyTS download attempts failed for: $fileName")
            return@withContext null
        } catch (e: Exception) {
            Log.e(TAG, "MyTS download error for $fileName", e)
            return@withContext null
        } finally {
            downloadMutex.withLock {
                downloading.remove(fileId)
            }
        }
    }

    /**
     * 解析 MyTS 聊天用户 ID 获取服务器地址。
     * 格式：@userId:serverHost
     * @return 服务器地址，失败返回空字符串
     */
    private fun parseMyTSServerHost(chatUserId: String): String {
        // 格式：@ahczygej657xpmfxxtf7ry3lsy2akckqti67clphushtpcv2pqcii===:chat-3.tmspk.net
        val lastColon = chatUserId.lastIndexOf(':')
        if (lastColon < 0) return ""
        return chatUserId.substring(lastColon + 1)
    }

    /**
     * 清理所有缓存文件。
     */
    fun clearCache(context: Context) {
        try {
            val dir = File(context.cacheDir, CACHE_DIR)
            if (dir.exists()) {
                dir.deleteRecursively()
                Log.d(TAG, "Cache cleared")
            }
        } catch (e: Exception) {
            Log.e(TAG, "Failed to clear cache", e)
        }
    }

    private fun getCacheFile(context: Context, fileId: String): File {
        // 使用 file_id 的 hash 作为文件名（避免特殊字符问题）
        val safeName = fileId.hashCode().toString(16)
        return File(context.cacheDir, "$CACHE_DIR/$safeName")
    }
}
