package com.tomhempel.rbarometer.questionnaire.handlers

import android.content.Context
import android.view.Gravity
import android.view.View
import android.widget.*
import com.tomhempel.rbarometer.questionnaire.GlobalValues
import com.tomhempel.rbarometer.LanguageManager
import com.tomhempel.rbarometer.data.AnswerRepository
import com.tomhempel.rbarometer.questionnaire.QuestionFlowResolver
import com.tomhempel.rbarometer.questionnaire.QuestionHandler
import com.tomhempel.rbarometer.questionnaire.QuestionItem
import com.tomhempel.rbarometer.R
import com.tomhempel.rbarometer.utils.ViewUtils
import kotlinx.coroutines.*

/*
Zweck:
- „Glas-Skala“-Frage: pro Symptom (Zeile) genau eine von fünf Stufen.
- Stufen als RadioButtons (clickbar) + Icon-Header.
- FIX: Pro Zeile wird Single-Select erzwungen (auch im Bearbeiten-Modus / Restore).
*/

class HandlerGlassScaleQuestion(
    private val context: Context,
    private val answers: MutableMap<String, Any>,
    private val languageID: String,
    private val goToNextQuestion: () -> Unit,
    private val goToPreviousQuestion: () -> Unit,
    private val goToQuestionById: (String) -> Unit,
    private val showToast: (String) -> Unit,
    private val questionnaireMeta: String,
    private val onAnswerChanged: () -> Unit = {},
) : QuestionHandler {

    private lateinit var layout: View
    private lateinit var question: QuestionItem.GlassScaleQuestion

    private val scaleLabels = listOf(
        "never_glass",
        "little_glass",
        "moderate_glass",
        "much_glass",
        "extreme_glass"
    )

    private fun symptomDisplayLabel(symptomKey: String): String {
        val translated = LanguageManager.getText(languageID, symptomKey)
        if (translated != symptomKey) return translated
        return (question.glassSymptoms ?: emptyList())
            .firstOrNull { it.key == symptomKey }
            ?.labelDe
            ?.takeIf { it.isNotBlank() }
            ?: symptomKey
    }

    private val glassIconForLabel = mapOf(
        "never_glass"    to R.drawable.ic_glass_0,
        "little_glass"   to R.drawable.ic_glass_1,
        "moderate_glass" to R.drawable.ic_glass_2,
        "much_glass"     to R.drawable.ic_glass_3,
        "extreme_glass"  to R.drawable.ic_glass_4,
    )

    private val thermometerIconForLabel = mapOf(
        "never_glass"    to R.drawable.ic_thermometer_0,
        "little_glass"   to R.drawable.ic_thermometer_1,
        "moderate_glass" to R.drawable.ic_thermometer_2,
        "much_glass"     to R.drawable.ic_thermometer_3,
        "extreme_glass"  to R.drawable.ic_thermometer_4,
    )

    private fun iconForLabel(labelKey: String): Int {
        val useThermometer = question.scaleType?.equals("thermometer", ignoreCase = true) == true
        val map = if (useThermometer) thermometerIconForLabel else glassIconForLabel
        return map[labelKey] ?: if (useThermometer) R.drawable.ic_thermometer_0 else R.drawable.ic_glass_0
    }

    // Damit wir beim programmatic-check keine Endlosschleifen triggern
    private var suppressRowListener: Boolean = false

    override fun bind(layout: View, question: QuestionItem) {
        if (question !is QuestionItem.GlassScaleQuestion) return
        this.layout = layout
        this.question = question

        val titleTv = layout.findViewById<TextView>(R.id.textView)
        val questionTv = layout.findViewById<TextView>(R.id.question)

        titleTv.text = question.textKey?.let { LanguageManager.getText(languageID, it) } ?: ""
        questionTv.text = question.question?.let { LanguageManager.getText(languageID, it) } ?: ""

        ViewUtils.setTextSizePercentOfScreenHeight(titleTv, 0.03f)
        ViewUtils.setTextSizePercentOfScreenHeight(questionTv, 0.03f)

        // Header Icons
        val header = layout.findViewById<LinearLayout>(R.id.glass_header)
        header.removeAllViews()
        header.addView(Space(context).apply {
            layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 4f)
        })

        val iconSizePx = (context.resources.displayMetrics.density * 36).toInt()
        scaleLabels.forEach { labelKey ->
            val cell = FrameLayout(context).apply {
                layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
            }
            val img = ImageView(context).apply {
                setImageResource(iconForLabel(labelKey))
                layoutParams = FrameLayout.LayoutParams(iconSizePx, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER)
                adjustViewBounds = true
                scaleType = ImageView.ScaleType.FIT_CENTER
            }
            cell.addView(img)
            header.addView(cell)
        }

        val tableLayout = layout.findViewById<TableLayout>(R.id.glass_table)
        tableLayout.removeAllViews()
        addSymptomRows(tableLayout)

        // Restore aus DB (nur wenn noch nicht im answers)
        val anySymptomNeedsRestore = question.symptoms.any { !answers.containsKey(it) }
        if (anySymptomNeedsRestore) {
            CoroutineScope(Dispatchers.IO).launch {
                try {
                    val clientCode = GlobalValues.LAST_CLIENT_CODE ?: return@launch
                    val allAnswersForClient = AnswerRepository.getAnswersForClient(clientCode)
                    val answerMap = allAnswersForClient.associateBy({ it.questionId }, { it.answerValue })

                    withContext(Dispatchers.Main) {
                        var anyRestored = false
                        for ((index, symptomKey) in question.symptoms.withIndex()) {
                            val answerMapKey = "$questionnaireMeta-$symptomKey"
                            val dbAnswer = answerMap[answerMapKey]?.takeIf { it.isNotBlank() }?.trim()
                            if (!answers.containsKey(symptomKey) && !dbAnswer.isNullOrBlank()) {
                                if (index < tableLayout.childCount) {
                                    val row = tableLayout.getChildAt(index) as? TableRow ?: continue
                                    val radioGroup = row.getChildAt(1) as? RadioGroup ?: continue
                                    setSingleSelection(radioGroup, dbAnswer)
                                    answers[symptomKey] = dbAnswer
                                    anyRestored = true
                                }
                            }
                        }
                        if (anyRestored) onAnswerChanged()
                    }
                } catch (_: Exception) { /* ignore */ }
            }
        }

        layout.findViewById<Button>(R.id.Qnext).setOnClickListener {
            if (validate()) {
                saveAnswer()
                QuestionFlowResolver.navigateAfterAnswer(
                    question.nextQuestionId,
                    goToQuestionById,
                    goToNextQuestion,
                )
            } else {
                showToast(LanguageManager.getText(languageID, "select_one_answer_per_row"))
            }
        }
        layout.findViewById<Button>(R.id.Qprev).setOnClickListener { goToPreviousQuestion() }
    }

    private fun addSymptomRows(table: TableLayout) {
        question.symptoms.forEach { symptomKey ->
            val savedLabel = answers[symptomKey] as? String

            val row = TableRow(context).apply {
                layoutParams = TableRow.LayoutParams(
                    TableRow.LayoutParams.MATCH_PARENT,
                    TableRow.LayoutParams.WRAP_CONTENT
                )
            }

            val symptomText = TextView(context).apply {
                text = symptomDisplayLabel(symptomKey)
                layoutParams = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT, 4f)
                setPadding(4, 16, 4, 16)
                ViewUtils.setTextSizePercentOfScreenHeight(this, 0.022f)
            }
            row.addView(symptomText)

            val radioGroup = RadioGroup(context).apply {
                orientation = RadioGroup.HORIZONTAL
                layoutParams = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT, 5f)
                setPadding(0, 0, 0, 0)
            }

            // Build buttons
            scaleLabels.forEach { labelKey ->
                val cell = FrameLayout(context).apply {
                    layoutParams = RadioGroup.LayoutParams(0, RadioGroup.LayoutParams.WRAP_CONTENT, 1f)
                }

                val rb = RadioButton(context).apply {
                    tag = labelKey
                    id = View.generateViewId()
                    isChecked = false
                    setPadding(0, 0, 0, 0)
                }

                rb.layoutParams = FrameLayout.LayoutParams(
                    FrameLayout.LayoutParams.WRAP_CONTENT,
                    FrameLayout.LayoutParams.WRAP_CONTENT,
                    Gravity.CENTER
                )

                // <<< FIX: erzwinge pro Zeile genau eine Auswahl
                rb.setOnCheckedChangeListener { buttonView, isChecked ->
                    if (suppressRowListener) return@setOnCheckedChangeListener
                    if (!isChecked) return@setOnCheckedChangeListener

                    val selectedLabel = buttonView.tag as? String ?: return@setOnCheckedChangeListener
                    // wenn einer checked -> alle anderen in dieser Row unchecken
                    suppressRowListener = true
                    try {
                        for (i in 0 until radioGroup.childCount) {
                            val other = getRadioFromChild(radioGroup.getChildAt(i)) ?: continue
                            if (other != buttonView) other.isChecked = false
                        }
                    } finally {
                        suppressRowListener = false
                    }

                    // Optional (wenn du willst): sofort im answers setzen (Edit-Mode fühlt sich dann "direkt" an)
                    answers[symptomKey] = selectedLabel
                }

                cell.addView(rb)
                radioGroup.addView(cell)
            }

            // Restore aus answers (falls vorhanden)
            if (!savedLabel.isNullOrBlank()) {
                setSingleSelection(radioGroup, savedLabel)
            }

            row.addView(radioGroup)
            table.addView(row)
        }
    }

    /**
     * Setzt in diesem Row-RadioGroup genau einen Wert aktiv und alle anderen aus.
     */
    private fun setSingleSelection(radioGroup: RadioGroup, labelKey: String) {
        suppressRowListener = true
        try {
            for (i in 0 until radioGroup.childCount) {
                val rb = getRadioFromChild(radioGroup.getChildAt(i)) ?: continue
                val tag = (rb.tag as? String)?.trim()
                rb.isChecked = (tag == labelKey.trim())
            }
        } finally {
            suppressRowListener = false
        }
    }

    override fun validate(): Boolean {
        val table = layout.findViewById<TableLayout>(R.id.glass_table)
        for (i in 0 until table.childCount) {
            val row = table.getChildAt(i) as TableRow
            val radioGroup = row.getChildAt(1) as RadioGroup
            var anyChecked = false
            for (j in 0 until radioGroup.childCount) {
                val rb = getRadioFromChild(radioGroup.getChildAt(j)) ?: continue
                if (rb.isChecked) { anyChecked = true; break }
            }
            if (!anyChecked) return false
        }
        return true
    }

    override fun saveAnswer() {
        val table = layout.findViewById<TableLayout>(R.id.glass_table)
        for (i in 0 until table.childCount) {
            val row = table.getChildAt(i) as TableRow
            val symptomKey = question.symptoms[i]
            val radioGroup = row.getChildAt(1) as RadioGroup

            for (j in 0 until radioGroup.childCount) {
                val rb = getRadioFromChild(radioGroup.getChildAt(j)) ?: continue
                if (rb.isChecked) {
                    answers[symptomKey] = rb.tag as String
                    break
                }
            }
        }
    }

    private fun getRadioFromChild(child: View): RadioButton? =
        when (child) {
            is RadioButton -> child
            is FrameLayout -> child.getChildAt(0) as? RadioButton
            else -> null
        }

}