package com.tomhempel.rbarometer.questionnaire.handlers

import android.content.Context
import android.view.View
import android.widget.*
import kotlinx.coroutines.*
import com.tomhempel.rbarometer.questionnaire.AnswerLookup
import com.tomhempel.rbarometer.questionnaire.AnswerRestoreHelper
import com.tomhempel.rbarometer.questionnaire.GlobalValues
import com.tomhempel.rbarometer.questionnaire.QuestionFlowResolver
import com.tomhempel.rbarometer.LanguageManager
import com.tomhempel.rbarometer.questionnaire.QuestionHandler
import com.tomhempel.rbarometer.questionnaire.QuestionItem
import com.tomhempel.rbarometer.questionnaire.SpinnerAnswerRules
import com.tomhempel.rbarometer.questionnaire.SpinnerSelectionHelper
import com.tomhempel.rbarometer.R
import com.tomhempel.rbarometer.utils.ViewUtils

class HandlerStringSpinner(
    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,
) : QuestionHandler {

    private lateinit var layout: View
    private lateinit var question: QuestionItem.StringSpinnerQuestion
    private var optionKeys: List<String> = emptyList()
    private var displayOptions: List<String> = emptyList()

    private var spinnerAdapterReady = false

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

        this.layout = layout
        this.question = question

        val questionTextView = layout.findViewById<TextView>(R.id.question)
        val textView = layout.findViewById<TextView>(R.id.textView)
        val spinner = layout.findViewById<Spinner>(R.id.string_spinner)

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

        ViewUtils.setTextSizePercentOfScreenHeight(textView, 0.03f)
        ViewUtils.setTextSizePercentOfScreenHeight(questionTextView, 0.03f)

        optionKeys = buildOptionKeys()
        displayOptions = SpinnerSelectionHelper.buildStringSpinnerItems(languageID, optionKeys)
        if (displayOptions.size <= 1) {
            showToast(LanguageManager.getText(languageID, "questionnaire_missing_options"))
            layout.findViewById<Button>(R.id.Qprev)?.setOnClickListener { goToPreviousQuestion() }
            return
        }

        val answerMapKey = question.question
        val savedSelection = AnswerLookup.stringValue(answers, question)
        applySpinnerSelection(spinner, savedSelection)

        if (savedSelection.isNullOrBlank()) {
            AnswerRestoreHelper.restoreIfMissing(
                CoroutineScope(Dispatchers.Main),
                questionnaireMeta,
                answerMapKey,
            ) { dbAnswer ->
                answers[answerMapKey] = dbAnswer
                answers[question.id] = dbAnswer
                applySpinnerSelection(spinner, dbAnswer)
            }
        }

        layout.findViewById<Button>(R.id.Qnext)?.setOnClickListener {
            if (!validate()) return@setOnClickListener
            saveAnswer()
            val selected = layout.findViewById<Spinner>(R.id.string_spinner).selectedItem as? String ?: ""
            val nextId = QuestionFlowResolver.nextQuestionIdForStringSpinner(question, languageID, selected)
            if (!nextId.isNullOrEmpty()) {
                goToQuestionById(nextId)
            } else {
                goToNextQuestion()
            }
        }

        layout.findViewById<Button>(R.id.Qprev)?.setOnClickListener { goToPreviousQuestion() }
    }

    /** Re-apply selection from [answers] (e.g. after all-in-one layout pass). */
    fun restoreSelectionFromAnswers() {
        if (!::layout.isInitialized) return
        val spinner = layout.findViewById<Spinner>(R.id.string_spinner) ?: return
        applySpinnerSelection(spinner, AnswerLookup.stringValue(answers, question))
    }

    override fun validate(): Boolean {
        val spinner = layout.findViewById<Spinner>(R.id.string_spinner)
        val selected = spinner.selectedItem as? String
        return if (SpinnerAnswerRules.isUnselected(languageID, selected)) {
            showToast(LanguageManager.getText(languageID, "select_one_answer"))
            false
        } else {
            true
        }
    }

    override fun saveAnswer() {
        val spinner = layout.findViewById<Spinner>(R.id.string_spinner)
        val selected = spinner.selectedItem as? String
        if (SpinnerAnswerRules.isUnselected(languageID, selected)) return
        val stored = selected?.trim() ?: return
        answers[question.question] = stored
        answers[question.id] = stored
    }

    private fun applySpinnerSelection(spinner: Spinner, saved: String?) {
        ensureSpinnerAdapter(spinner)
        val index = SpinnerSelectionHelper.indexForSavedValue(
            languageID,
            displayOptions,
            saved,
            optionKeys,
        )
        if (index < 0) return
        if ((spinner.adapter?.count ?: 0) > index) {
            spinner.setSelection(index, false)
        }
    }

    private fun ensureSpinnerAdapter(spinner: Spinner) {
        if (spinnerAdapterReady && spinner.adapter != null) return
        ViewUtils.setupResponsiveSpinner(context, spinner, displayOptions, null)
        spinnerAdapterReady = true
    }

    private fun buildOptionKeys(): List<String> {
        val base = (question.options ?: emptyList()).map { it.trim() }.filter { it.isNotEmpty() }
        val otherKey = question.otherOptionKey?.trim()?.takeIf { it.isNotEmpty() }
        return if (otherKey != null && !question.otherNextQuestionId.isNullOrBlank()) {
            if (base.none { it.equals(otherKey, ignoreCase = true) }) base + otherKey else base
        } else {
            base
        }
    }
}
