package com.dano.test1.questionnaire

import android.R
import android.app.Activity
import android.util.Log
import android.view.View
import android.widget.*
import com.dano.test1.LanguageManager
import com.dano.test1.MainActivity
import com.dano.test1.MyApp
import com.dano.test1.data.*
import com.dano.test1.questionnaire.handlers.HandlerClientCoachCode
import com.dano.test1.questionnaire.handlers.HandlerClientNotSigned
import com.dano.test1.questionnaire.handlers.HandlerDateSpinner
import com.dano.test1.questionnaire.handlers.HandlerGlassScaleQuestion
import com.dano.test1.questionnaire.handlers.HandlerLastPage
import com.dano.test1.questionnaire.handlers.HandlerMultiCheckboxQuestion
import com.dano.test1.questionnaire.handlers.HandlerRadioQuestion
import com.dano.test1.questionnaire.handlers.HandlerStringSpinner
import com.dano.test1.questionnaire.handlers.HandlerValueSpinner
import com.google.gson.Gson
import com.google.gson.JsonParser
import kotlinx.coroutines.*
import java.io.File
import java.util.Calendar

const val MAX_VALUE_AGE = 122
val MAX_VALUE_YEAR = Calendar.getInstance().get(Calendar.YEAR)

object GlobalValues {
    var INTEGRATION_INDEX: Int = 0
    var LAST_CLIENT_CODE: String? = null
    var LOADED_CLIENT_CODE: String? = null
}

data class QuestionnaireMeta(val id: String)
data class QuestionnaireData(val meta: QuestionnaireMeta, val questions: List<QuestionItem>)

abstract class QuestionnaireBase<T> {
    abstract fun startQuestionnaire()
    abstract fun showCurrentQuestion()

    fun attach(activity: Activity, language: String) {
        this.context = activity
        this.languageID = language
    }

    protected lateinit var questionnaireMeta: QuestionnaireMeta
    protected var currentIndex = 0
    protected lateinit var questions: List<QuestionItem>
    protected val answers = mutableMapOf<String, Any>()
    protected val points = mutableListOf<Int>()
    protected var languageID: String = "GERMAN"
    protected lateinit var context: Activity
    private val navigationHistory = mutableListOf<Int>()

    protected fun showToast(message: String) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
    }

    protected fun validateEditTexts(vararg fields: EditText): Boolean {
        return fields.all { it.text.toString().trim().isNotEmpty() }
    }

    protected fun updateFileContent(fileName: String, placeholders: Map<String, Any?>) {
        val file = File(context.filesDir, fileName)
        if (file.exists()) {
            var updatedContent = file.readText()
            placeholders.forEach { (key, value) ->
                updatedContent = updatedContent.replace("{$key}", value.toString())
            }
            file.writeText(updatedContent)
        }
    }

    protected fun setupSpinner(spinner: Spinner, spinnerValues: List<Any>, selectedValue: Any?) {
        val adapter = ArrayAdapter(context, R.layout.simple_spinner_item, spinnerValues).apply {
            setDropDownViewResource(R.layout.simple_spinner_dropdown_item)
        }
        spinner.adapter = adapter
        selectedValue?.let { value ->
            val index = spinnerValues.indexOfFirst {
                it.toString().trim().equals(value.toString().trim(), ignoreCase = true)
            }
            if (index >= 0) spinner.setSelection(index)
        }
    }

    protected fun navigateTo(layoutResId: Int, setup: (View) -> Unit) {
        context.setContentView(layoutResId)
        val rootView = context.findViewById<View>(R.id.content)
        setup(rootView)
    }

    protected fun setupPrevButton(buttonId: Int, action: () -> Unit) {
        context.findViewById<Button>(buttonId)?.setOnClickListener { action() }
    }

    protected fun showEmptyScreen() {
        navigateTo(getLayoutResId("empty")) {
            setupPrevButton(com.dano.test1.R.id.Qprev) { goToPreviousQuestion() }
        }
    }

    protected fun getLayoutResId(layoutName: String?): Int {
        return layoutName?.let {
            context.resources.getIdentifier(it, "layout", context.packageName)
        } ?: 0
    }

    protected fun calculateIntegrationIndex(): Int = points.sum()

    protected fun goToPreviousQuestion() {
        if (navigationHistory.isNotEmpty()) {
            currentIndex = navigationHistory.removeAt(navigationHistory.size - 1)
            showCurrentQuestion()
        } else {
            (context as? MainActivity)?.finishQuestionnaire()
        }
    }

    protected fun goToNextQuestion() {
        if (currentIndex < questions.size - 1) {
            navigationHistory.add(currentIndex)
            currentIndex++
            showCurrentQuestion()
        }
    }

    fun goToQuestionById(questionId: String) {
        val index = questions.indexOfFirst { it.id == questionId }
        if (index != -1) {
            navigationHistory.add(currentIndex)
            currentIndex = index
            showCurrentQuestion()
        }
    }

    protected fun loadQuestionnaireFromJson(filename: String): Pair<QuestionnaireMeta, List<QuestionItem>> {
        val jsonString = context.assets.open(filename).bufferedReader().use { it.readText() }
        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 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,
            "glass_scale_question" to QuestionItem.GlassScaleQuestion::class.java,
            "last_page" to QuestionItem.LastPage::class.java,
            "client_not_signed" to QuestionItem.ClientNotSigned::class.java,
            "string_spinner" to QuestionItem.StringSpinnerQuestion::class.java,
            "multi_check_box_question" to QuestionItem.MultiCheckboxQuestion::class.java
        )

        val questionsList = jsonArray.mapNotNull { element ->
            val obj = element.asJsonObject
            val layoutType = obj.get("layout").asString
            val clazz = questionTypeMap[layoutType] ?: return@mapNotNull null
            gson.fromJson(obj, clazz)
        }

        return Pair(meta, questionsList)
    }

    protected open fun createHandlerForQuestion(question: QuestionItem): QuestionHandler? {
        return when (question) {
            is QuestionItem.RadioQuestion -> HandlerRadioQuestion(context, answers, points, languageID, ::goToNextQuestion, ::goToPreviousQuestion, ::goToQuestionById, ::showToast, questionnaireMeta.id)
            is QuestionItem.ClientCoachCodeQuestion -> HandlerClientCoachCode(answers, languageID, ::goToNextQuestion, ::goToPreviousQuestion, ::showToast)
            is QuestionItem.DateSpinnerQuestion -> HandlerDateSpinner(context, answers, languageID, ::goToNextQuestion, ::goToPreviousQuestion, ::showToast, questionnaireMeta.id)
            is QuestionItem.ValueSpinnerQuestion -> HandlerValueSpinner(context, answers, languageID, ::goToNextQuestion, ::goToPreviousQuestion, ::goToQuestionById, ::showToast, questionnaireMeta.id)
            is QuestionItem.GlassScaleQuestion -> HandlerGlassScaleQuestion(context, answers, points, languageID, ::goToNextQuestion, ::goToPreviousQuestion, ::showToast, questionnaireMeta.id)
            is QuestionItem.ClientNotSigned -> HandlerClientNotSigned(answers, languageID, ::goToNextQuestion, ::goToPreviousQuestion, ::showToast)
            is QuestionItem.StringSpinnerQuestion -> HandlerStringSpinner(context, answers, languageID, ::goToNextQuestion, ::goToPreviousQuestion, ::showToast, questionnaireMeta.id)
            is QuestionItem.MultiCheckboxQuestion -> HandlerMultiCheckboxQuestion(context, answers, points, languageID, ::goToNextQuestion, ::goToPreviousQuestion, ::showToast, questionnaireMeta.id)
            is QuestionItem.LastPage -> HandlerLastPage(
                answers, languageID, ::goToNextQuestion, ::goToPreviousQuestion
            ) { CoroutineScope(Dispatchers.IO).launch { saveAnswersToDatabase(answers, questionnaireMeta.id) } }
            else -> null
        }
    }

    suspend fun saveAnswersToDatabase(answers: Map<String, Any>, questionnaireId: String) {
        Log.d("AnswersMap", answers.toString())
        val db = MyApp.database

        val clientCode = answers["client_code"] as? String ?: return

        saveClientAndQuestionnaire(db, clientCode, questionnaireId)

        // 🔥 Vor dem Speichern alte Antworten löschen
        db.answerDao().deleteAnswersForClientAndQuestionnaire(clientCode, questionnaireId)

        saveQuestions(db, answers, questionnaireId)
        saveAnswers(db, answers, questionnaireId, clientCode)
        markQuestionnaireCompleted(db, questionnaireId, clientCode)
    }


    private suspend fun saveClientAndQuestionnaire(db: AppDatabase, clientCode: String, questionnaireId: String) {
        db.clientDao().insertClient(Client(clientCode))
        db.questionnaireDao().insertQuestionnaire(Questionnaire(id = questionnaireId))
    }

    private suspend fun saveQuestions(db: AppDatabase, answers: Map<String, Any>, questionnaireId: String) {
        val questionEntities = answers.keys
            .filterNot { it.startsWith("client") }
            .map { key ->
                val questionId = "$questionnaireId-$key"
                Question(
                    questionId = questionId,
                    questionnaireId = questionnaireId,
                    question = LanguageManager.getText(languageID, key)
                )
            }
        db.questionDao().insertQuestions(questionEntities)
    }

    private suspend fun saveAnswers(db: AppDatabase, answers: Map<String, Any>, questionnaireId: String, clientCode: String) {
        val answerEntities = answers.entries
            .filterNot { it.key.startsWith("client") }
            .map { (key, value) ->
                val questionId = "$questionnaireId-$key"
                Answer(
                    clientCode = clientCode,
                    questionId = questionId,
                    answerValue = value.toString()
                )
            }
        db.answerDao().insertAnswers(answerEntities)
    }

    private suspend fun markQuestionnaireCompleted(db: AppDatabase, questionnaireId: String, clientCode: String) {
        val completedEntry = CompletedQuestionnaire(
            clientCode = clientCode,
            questionnaireId = questionnaireId,
            isDone = true,
            sumPoints = points.sum()
        )
        db.completedQuestionnaireDao().insert(completedEntry)
    }

    fun endQuestionnaire() {
        (context as? MainActivity)?.finishQuestionnaire()
    }
}
