package com.tomhempel.rbarometer.questionnaire

import android.content.Context
import com.tomhempel.rbarometer.network.QuestionnaireCache
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.JsonParser

object QuestionnaireJsonLoader {

    fun load(context: Context, filename: String): Pair<QuestionnaireMeta, List<QuestionItem>> {
        val jsonString = QuestionnaireCache.loadQuestionnaireJson(context, filename)
            ?: throw IllegalStateException("No synced questionnaire for $filename — refresh from server first.")
        QuestionnaireCache.applyQuestionnaireTranslationsFromJson(jsonString)
        val gson = Gson()
        val jsonObject = JsonParser.parseString(jsonString).asJsonObject
        val meta = gson.fromJson(jsonObject.getAsJsonObject("meta"), QuestionnaireMeta::class.java)
        val jsonArray = jsonObject.getAsJsonArray("questions")
        val questionsList = jsonArray.mapNotNull { element ->
            val obj = element.asJsonObject
            val layoutType = obj.get("layout").asString
            val clazz = questionTypeMap[layoutType] ?: return@mapNotNull null
            gson.fromJson(normalizeQuestionObject(obj), clazz)
        }
        return Pair(meta, questionsList)
    }

    private val questionTypeMap = mapOf(
        "client_coach_code_question" to QuestionItem.ClientCoachCodeQuestion::class.java,
        "radio_question" to QuestionItem.RadioQuestion::class.java,
        "date_spinner" to QuestionItem.DateSpinnerQuestion::class.java,
        "value_spinner" to QuestionItem.ValueSpinnerQuestion::class.java,
        "slider_question" to QuestionItem.SliderQuestion::class.java,
        "glass_scale_question" to QuestionItem.GlassScaleQuestion::class.java,
        "last_page" to QuestionItem.LastPage::class.java,
        "string_spinner" to QuestionItem.StringSpinnerQuestion::class.java,
        "multi_check_box_question" to QuestionItem.MultiCheckboxQuestion::class.java,
        "free_text" to QuestionItem.FreeTextQuestion::class.java,
    )

    private fun normalizeQuestionObject(obj: JsonObject): JsonObject {
        val copy = obj.deepCopy()
        when (copy.get("layout")?.asString) {
            "string_spinner" -> {
                val options = copy.getAsJsonArray("options") ?: return copy
                if (options.size() == 0) return copy
                val normalized = com.google.gson.JsonArray()
                options.forEach { option ->
                    when {
                        option.isJsonPrimitive -> {
                            val text = option.asString.trim()
                            if (text.isNotEmpty()) normalized.add(text)
                        }
                        option.isJsonObject -> {
                            val key = option.asJsonObject.get("key")?.asString?.trim().orEmpty()
                            if (key.isNotEmpty()) normalized.add(key)
                        }
                    }
                }
                if (normalized.size() > 0) copy.add("options", normalized)
            }
            "glass_scale_question" -> {
                if (!copy.has("glassSymptoms") || copy.get("glassSymptoms").isJsonNull) {
                    copy.add("glassSymptoms", com.google.gson.JsonArray())
                }
            }
            "value_spinner" -> {
                val options = copy.getAsJsonArray("options")
                if (options != null && options.any { it.isJsonObject && !it.asJsonObject.has("value") }) {
                    val normalized = com.google.gson.JsonArray()
                    options.forEach { option ->
                        if (option.isJsonObject) {
                            val key = option.asJsonObject.get("key")?.asString
                            val number = key?.toIntOrNull()
                            if (number != null) {
                                val valueObj = JsonObject()
                                valueObj.addProperty("value", number)
                                option.asJsonObject.get("nextQuestionId")?.let {
                                    valueObj.add("nextQuestionId", it)
                                }
                                normalized.add(valueObj)
                            }
                        } else {
                            normalized.add(option)
                        }
                    }
                    copy.add("options", normalized)
                }
            }
        }
        return copy
    }
}
