package com.example.app

import android.content.Context
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream
import java.net.HttpURLConnection
import java.net.URL
import java.util.zip.ZipInputStream
import org.json.JSONObject

/**
 * Simple updater that checks a remote JSON for latest version and zip URL,
 * downloads and unpacks into internal storage under filesDir/webapp.
 * This is intentionally minimal — adapt URLs and error handling as needed.
 */
class WebAppUpdater(private val context: Context) {
    private val TAG = "WebAppUpdater"
    // control URL on your server; update if your JSON lives at a different path
    private val controlUrl = "https://edu.aln.webd.pl/app/latest.json"
    private val targetDirName = "webapp"

    fun checkAndUpdate(onComplete: (() -> Unit)? = null) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val conn = URL(controlUrl).openConnection() as HttpURLConnection
                conn.connectTimeout = 5000
                conn.readTimeout = 10000
                conn.requestMethod = "GET"
                if (conn.responseCode != 200) {
                    Log.w(TAG, "control.json fetch failed: ${conn.responseCode}")
                    onComplete?.invoke()
                    return@launch
                }
                val text = conn.inputStream.bufferedReader().use { it.readText() }
                // expecting: { "version": "1.0.1", "zip": "https://.../app.zip" }
                val json = JSONObject(text)
                val zipUrl = if (json.has("zip")) json.getString("zip") else null
                val version = if (json.has("version")) json.getString("version") else null

                if (zipUrl.isNullOrEmpty() || version.isNullOrEmpty()) {
                    Log.w(TAG, "invalid control.json: $text")
                    onComplete?.invoke()
                    return@launch
                }

                val versionFile = File(context.filesDir, "$targetDirName/.version")
                val currentVersion = if (versionFile.exists()) versionFile.readText().trim() else ""
                if (currentVersion == version) {
                    Log.i(TAG, "webapp up-to-date: $version")
                    onComplete?.invoke()
                    return@launch
                }

                // download zip
                val tmpZip = File.createTempFile("webapp", ".zip", context.cacheDir)
                downloadToFile(zipUrl, tmpZip)

                // unpack to temp dir then move
                val tmpDir = File.createTempFile("webapptemp", "", context.cacheDir)
                tmpDir.delete()
                tmpDir.mkdirs()
                unzipToDir(tmpZip, tmpDir)

                val targetDir = File(context.filesDir, targetDirName)
                if (targetDir.exists()) targetDir.deleteRecursively()
                tmpDir.renameTo(targetDir)

                versionFile.writeText(version)
                Log.i(TAG, "webapp updated to $version")
            } catch (e: Exception) {
                Log.w(TAG, "update failed", e)
            } finally {
                onComplete?.invoke()
            }
        }
    }

    private fun downloadToFile(urlStr: String, outFile: File) {
        val url = URL(urlStr)
        val conn = url.openConnection() as HttpURLConnection
        conn.connectTimeout = 5000
        conn.readTimeout = 20000
        conn.requestMethod = "GET"
        conn.connect()
        if (conn.responseCode != 200) throw RuntimeException("download failed: ${conn.responseCode}")
        conn.inputStream.use { input ->
            FileOutputStream(outFile).use { fos ->
                input.copyTo(fos)
            }
        }
    }

    private fun unzipToDir(zipFile: File, targetDir: File) {
        ZipInputStream(BufferedInputStream(zipFile.inputStream())).use { zis ->
            var entry = zis.nextEntry
            while (entry != null) {
                val out = File(targetDir, entry.name)
                if (entry.isDirectory) {
                    out.mkdirs()
                } else {
                    out.parentFile?.mkdirs()
                    FileOutputStream(out).use { fos ->
                        zis.copyTo(fos)
                    }
                }
                entry = zis.nextEntry
            }
        }
    }

    fun getLocalWebAppPath(): String? {
        val dir = File(context.filesDir, targetDirName)
        return if (dir.exists()) dir.absolutePath else null
    }
}
