package com.radiola.update

import android.content.Context
import android.content.Intent
import android.os.Environment
import android.util.Log
import androidx.core.content.FileProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONObject
import java.io.File
import java.security.MessageDigest
import java.util.concurrent.TimeUnit

/** Описание последней версии из манифеста бэкенда (/app-version). */
data class VersionInfo(
    val versionName: String,
    val versionCode: Int,
    val downloadUrl: String,
    val forceUpdate: Boolean,
    val sha256: String?,
    val notes: String?
)

/**
 * Авто-обновление APK (по образцу nkVPN). Бэкенд отдаёт манифест /app-version с
 * version_code последней сборки и ссылкой на APK; если он новее установленного —
 * скачиваем во внутреннюю папку, проверяем SHA-256 и запускаем системный установщик
 * через FileProvider. Так пользователю не нужно заходить в маркет.
 */
object UpdateManager {
    private const val TAG = "radiOLA/Update"
    private const val BASE_URL = "http://121.127.37.212:3000"

    private val client = OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(120, TimeUnit.SECONDS)
        .build()

    /** Запрашивает манифест версии. null — сеть/парсинг не удались (молча, не мешаем работе). */
    suspend fun checkUpdate(): VersionInfo? = withContext(Dispatchers.IO) {
        try {
            val request = Request.Builder().url("$BASE_URL/app-version").build()
            client.newCall(request).execute().use { resp ->
                if (!resp.isSuccessful) return@withContext null
                val body = resp.body?.string() ?: return@withContext null
                val a = JSONObject(body).getJSONObject("android")
                VersionInfo(
                    versionName = a.getString("version_name"),
                    versionCode = a.getInt("version_code"),
                    downloadUrl = a.getString("download_url"),
                    forceUpdate = a.optBoolean("force_update", false),
                    sha256 = a.optString("sha256", "").ifBlank { null },
                    notes = a.optString("notes", "").ifBlank { null }
                )
            }
        } catch (e: Exception) {
            Log.w(TAG, "checkUpdate failed: ${e.message}")
            null
        }
    }

    /** Скачивает APK во внутреннюю Download-папку приложения, шлёт прогресс 0..100. */
    suspend fun downloadApk(
        context: Context,
        url: String,
        onProgress: (Int) -> Unit
    ): File? = withContext(Dispatchers.IO) {
        try {
            val request = Request.Builder().url(url).build()
            client.newCall(request).execute().use { resp ->
                if (!resp.isSuccessful) return@withContext null
                val total = resp.body?.contentLength() ?: -1L
                val dir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
                val file = File(dir, "radiola-update.apk")
                var downloaded = 0L
                resp.body?.byteStream()?.use { input ->
                    file.outputStream().use { output ->
                        val buffer = ByteArray(8192)
                        var bytes: Int
                        while (input.read(buffer).also { bytes = it } != -1) {
                            output.write(buffer, 0, bytes)
                            downloaded += bytes
                            if (total > 0) onProgress((downloaded * 100 / total).toInt())
                        }
                    }
                }
                file
            }
        } catch (e: Exception) {
            Log.e(TAG, "downloadApk failed: ${e.message}")
            null
        }
    }

    /**
     * Сверяет SHA-256 скачанного APK с манифестом — защита от подмены (APK тянем по
     * HTTP) и битой загрузки. Если суммы в манифесте нет — пропускаем (true).
     */
    fun verifySha256(file: File, expected: String?): Boolean {
        if (expected.isNullOrBlank()) return true
        return try {
            val digest = MessageDigest.getInstance("SHA-256")
            file.inputStream().use { input ->
                val buffer = ByteArray(8192)
                var bytes: Int
                while (input.read(buffer).also { bytes = it } != -1) {
                    digest.update(buffer, 0, bytes)
                }
            }
            val hex = digest.digest().joinToString("") { "%02x".format(it) }
            hex.equals(expected.trim(), ignoreCase = true)
        } catch (e: Exception) {
            Log.e(TAG, "verifySha256 failed: ${e.message}")
            false
        }
    }

    /** Запускает системный установщик APK через FileProvider. */
    fun installApk(context: Context, file: File) {
        try {
            val uri = FileProvider.getUriForFile(
                context,
                "${context.packageName}.fileprovider",
                file
            )
            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)
            }
            context.startActivity(intent)
        } catch (e: Exception) {
            Log.e(TAG, "installApk failed: ${e.message}")
        }
    }
}
