package com.dano.test1.network

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.util.Base64
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import android.database.Cursor
import com.dano.test1.AES256Helper
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.asRequestBody
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.io.IOException
import kotlin.system.exitProcess

object DatabaseUploader {

    private const val DB_NAME = "questionnaire_database"
    private const val SERVER_DELTA_URL = "https://daniel-ocks.de/qdb/uploadDeltaTest5.php"
    private const val SERVER_CHECK_URL = "https://daniel-ocks.de/qdb/checkDatabaseExists.php"

    private val client = OkHttpClient()

    private fun uploadDatabase(context: Context, token: String) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val dbFile = context.getDatabasePath(DB_NAME)
                if (!dbFile.exists()) {
                    Log.e("UPLOAD", "DB fehlt: ${dbFile.absolutePath}")
                    return@launch
                }

                // WAL sauber schließen (falls aktiv)
                try {
                    val db = SQLiteDatabase.openDatabase(dbFile.absolutePath, null, SQLiteDatabase.OPEN_READWRITE)
                    db.rawQuery("PRAGMA wal_checkpoint(FULL);", null).use { /* noop */ }
                    db.close()
                } catch (_: Exception) { }

                checkDatabaseExists()
                uploadPseudoDelta(context, dbFile, token)
            } catch (e: Exception) {
                Log.e("UPLOAD", "Fehler", e)
            }
        }
    }

    private fun checkDatabaseExists(): Boolean {
        return try {
            val req = Request.Builder().url(SERVER_CHECK_URL).get().build()
            client.newCall(req).execute().use { resp ->
                if (!resp.isSuccessful) return false
                val body = resp.body?.string() ?: return false
                try { JSONObject(body).optBoolean("exists", false) } catch (_: Exception) { false }
            }
        } catch (e: Exception) { false }
    }

    private fun uploadPseudoDelta(context: Context, file: File, token: String) {
        try {
            val db = SQLiteDatabase.openDatabase(file.absolutePath, null, SQLiteDatabase.OPEN_READONLY)
            val data = JSONObject().apply {
                put("clients", queryToJsonArray(db, "SELECT clientCode FROM clients"))
                put("questionnaires", queryToJsonArray(db, "SELECT id FROM questionnaires"))
                put("questions", queryToJsonArray(db, "SELECT questionId, questionnaireId, question FROM questions"))
                put("answers", queryToJsonArray(db, "SELECT clientCode, questionId, answerValue FROM answers"))
                put(
                    "completed_questionnaires",
                    queryToJsonArray(db, "SELECT clientCode, questionnaireId, timestamp, isDone, sumPoints FROM completed_questionnaires")
                )
            }
            db.close()

            // JSON -> verschlüsselte Payload
            val tmpJson = File(context.cacheDir, "payload.json").apply { writeText(data.toString()) }
            val tmpEnc = File(context.cacheDir, "payload.enc")
            try {
                AES256Helper.encryptFileWithToken(tmpJson, tmpEnc, token)
            } catch (e: Exception) {
                Log.e("UPLOAD", "Verschlüsselung fehlgeschlagen", e)
                tmpJson.delete(); return
            }

            val body = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("token", token) // bleibt für Kompatibilität enthalten
                .addFormDataPart("file", "payload.enc", tmpEnc.asRequestBody("application/octet-stream".toMediaType()))
                .build()

            // WICHTIG: Jetzt HTTPS + Konstanten-URL verwenden, plus Bearer-Header
            val request = Request.Builder()
                .url(SERVER_DELTA_URL)
                .post(body)
                .header("Authorization", "Bearer $token")
                .build()

            client.newCall(request).enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    Log.e("UPLOAD", "Fehlgeschlagen: ${e.message}")
                    tmpJson.delete(); tmpEnc.delete()
                }
                override fun onResponse(call: Call, response: Response) {
                    val respBody = try { response.body?.string() ?: "" } catch (_: Exception) { "" }
                    if (response.isSuccessful) {
                        Log.d("UPLOAD", "OK: $respBody")

                        // alte Logik: lokale DB + Neben­dateien löschen
                        try {
                            if (!file.delete()) Log.w("UPLOAD", "Lokale DB nicht gelöscht.")
                            File(file.parent, "${file.name}-journal").delete()
                            File(file.parent, "${file.name}-wal").delete()
                            File(file.parent, "${file.name}-shm").delete()
                        } catch (e: Exception) {
                            Log.w("UPLOAD", "Fehler beim Löschen lokaler DB-Dateien", e)
                        }
                    } else {
                        Log.e("UPLOAD", "HTTP ${response.code}: $respBody")
                    }
                    tmpJson.delete(); tmpEnc.delete()

                    // unverändert beibehalten
                    try { exitProcess(0) } catch (_: Exception) {}
                }
            })
        } catch (e: Exception) {
            Log.e("UPLOAD", "Exception", e)
        }
    }

    private fun queryToJsonArray(db: SQLiteDatabase, query: String): JSONArray {
        val c = db.rawQuery(query, null)
        val arr = JSONArray()
        c.use {
            val cols = it.columnNames
            while (it.moveToNext()) {
                val obj = JSONObject()
                for (col in cols) {
                    val idx = it.getColumnIndex(col)
                    if (idx >= 0) {
                        when (it.getType(idx)) {
                            Cursor.FIELD_TYPE_INTEGER -> obj.put(col, it.getLong(idx))
                            Cursor.FIELD_TYPE_FLOAT -> obj.put(col, it.getDouble(idx))
                            Cursor.FIELD_TYPE_STRING -> obj.put(col, it.getString(idx))
                            Cursor.FIELD_TYPE_NULL -> obj.put(col, JSONObject.NULL)
                            Cursor.FIELD_TYPE_BLOB -> obj.put(col, Base64.encodeToString(it.getBlob(idx), Base64.NO_WRAP))
                            else -> obj.put(col, it.getString(idx))
                        }
                    }
                }
                arr.put(obj)
            }
        }
        return arr
    }

    fun uploadDatabaseWithToken(context: Context, token: String) {
        uploadDatabase(context, token)
    }


}
