package com.a2i.forwarder.core

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import androidx.core.content.FileProvider
import com.a2i.forwarder.A2iApp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONObject
import java.io.File
import java.util.concurrent.TimeUnit

data class UpdateInfo(
    val latestVersion: String,
    val apkUrl: String,
    val apkSize: Long,
    val releaseNotes: String,
    val releasePageUrl: String,
)

/**
 * 应用内更新：拉取 GitHub Releases 最新版 → 版本比较 → 下载 APK → 调起系统安装器。
 * Android targetSdk≥24 须用 FileProvider，targetSdk≥26 安装未知来源 APK 须 REQUEST_INSTALL_PACKAGES。
 */
class UpdateChecker(private val context: Context) {
    private val app get() = A2iApp.instance
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    private val http = OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .build()

    val updateInfo = MutableStateFlow<UpdateInfo?>(null)
    val downloading = MutableStateFlow(false)
    val downloadProgress = MutableStateFlow(0)        // 0..100
    val lastError = MutableStateFlow<String?>(null)

    fun start() {
        scope.launch { check(force = false) }
    }

    suspend fun check(force: Boolean): Result<UpdateInfo?> = withContext(Dispatchers.IO) {
        runCatching {
            val settings = app.settings
            val now = System.currentTimeMillis()
            if (!force) {
                // 自动检查被关闭或未满 24h：保持现状，不发请求
                if (!settings.updateCheckEnabled.value) return@runCatching updateInfo.value
                if (now - settings.lastUpdateCheckTime.value < CHECK_INTERVAL_MS) return@runCatching updateInfo.value
            }
            val req = Request.Builder()
                .url(RELEASES_API)
                .header("Accept", "application/json")
                .header("User-Agent", "a2i-android")
                .get()
                .build()
            val info = http.newCall(req).execute().use { res ->
                if (!res.isSuccessful) error("HTTP ${res.code}")
                val body = res.body?.string() ?: error("空响应")
                parseRelease(body)
            }
            settings.setLastUpdateCheck(now)
            val current = currentVersionName()
            val available = info != null &&
                isNewer(info.latestVersion, current) &&
                info.latestVersion != settings.ignoredVersion.value
            updateInfo.value = if (available) info else null
            lastError.value = null
            updateInfo.value
        }.onFailure { lastError.value = it.message ?: "检查失败" }
    }

    private fun parseRelease(body: String): UpdateInfo? {
        val json = JSONObject(body)
        val tag = json.optString("tag_name").removePrefix("v").trim()
        if (tag.isEmpty()) return null
        val assets = json.optJSONArray("assets") ?: return null
        var apkUrl = ""
        var apkSize = 0L
        for (i in 0 until assets.length()) {
            val a = assets.optJSONObject(i) ?: continue
            if (a.optString("name").endsWith(".apk", ignoreCase = true)) {
                apkUrl = a.optString("browser_download_url")
                apkSize = a.optLong("size")
                break
            }
        }
        if (apkUrl.isEmpty()) return null
        return UpdateInfo(
            latestVersion = tag,
            apkUrl = apkUrl,
            apkSize = apkSize,
            releaseNotes = json.optString("body").orEmpty(),
            releasePageUrl = json.optString("html_url").orEmpty(),
        )
    }

    suspend fun download(info: UpdateInfo): File? = withContext(Dispatchers.IO) {
        downloading.value = true
        downloadProgress.value = 0
        lastError.value = null
        try {
            val req = Request.Builder().url(info.apkUrl).get().build()
            http.newCall(req).execute().use { res ->
                if (!res.isSuccessful) { lastError.value = "HTTP ${res.code}"; return@use null }
                val body = res.body ?: run { lastError.value = "空响应"; return@use null }
                val total = body.contentLength()
                val dir = context.getExternalFilesDir(null) ?: context.cacheDir
                val target = File(dir, "a2i-${info.latestVersion}.apk")
                target.outputStream().use { sink ->
                    val input = body.byteStream()
                    val buf = ByteArray(8 * 1024)
                    var read = 0L
                    while (true) {
                        val n = input.read(buf)
                        if (n <= 0) break
                        sink.write(buf, 0, n)
                        read += n
                        if (total > 0) downloadProgress.value = (read * 100 / total).toInt()
                    }
                }
                downloadProgress.value = 100
                target
            }
        } catch (e: Exception) {
            lastError.value = e.message ?: "下载失败"
            null
        } finally {
            downloading.value = false
        }
    }

    fun install(apk: File) {
        // 国产 ROM 需用户先在系统设置开启「安装未知应用」
        if (!context.packageManager.canRequestPackageInstalls()) {
            val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
                data = Uri.parse("package:${context.packageName}")
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            runCatching { context.startActivity(intent) }
            return
        }
        val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", apk)
        val intent = Intent(Intent.ACTION_VIEW).apply {
            setDataAndType(uri, "application/vnd.android.package-archive")
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        runCatching { context.startActivity(intent) }
    }

    fun ignoreVersion(v: String) {
        scope.launch {
            app.settings.setIgnoredVersion(v)
            updateInfo.value = null
        }
    }

    private fun currentVersionName(): String {
        return runCatching {
            @Suppress("DEPRECATION")
            context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: "0"
        }.getOrDefault("0")
    }

    /** 语义版本比较：按 "." 分段逐段比，段数不等时短的补 0。 */
    fun isNewer(latest: String, current: String): Boolean {
        val l = latest.split(".").map { it.substringBefore("-").toIntOrNull() ?: 0 }
        val c = current.split(".").map { it.substringBefore("-").toIntOrNull() ?: 0 }
        val n = maxOf(l.size, c.size)
        for (i in 0 until n) {
            val lv = l.getOrElse(i) { 0 }
            val cv = c.getOrElse(i) { 0 }
            if (lv != cv) return lv > cv
        }
        return false
    }

    companion object {
        // 更新源用自建 Gitea（git.sunlunfan.com，国内可达），避免 api.github.com 不稳
        const val RELEASES_API = "https://git.sunlunfan.com/api/v1/repos/song/a2i/releases/latest"
        const val CHECK_INTERVAL_MS = 24L * 60 * 60 * 1000
    }
}
