package eu.gaudian.translator.model.grammar

import eu.gaudian.translator.model.grammar.GrammarConstants.ACCUSATIVE
import eu.gaudian.translator.model.grammar.GrammarConstants.DATIVE
import eu.gaudian.translator.model.grammar.GrammarConstants.GENITIVE
import eu.gaudian.translator.model.grammar.GrammarConstants.KEY_FORM
import eu.gaudian.translator.model.grammar.GrammarConstants.KEY_TAGS
import eu.gaudian.translator.model.grammar.GrammarConstants.NOMINATIVE
import eu.gaudian.translator.model.grammar.GrammarConstants.PLURAL
import eu.gaudian.translator.model.grammar.GrammarConstants.SINGULAR
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

object SharedMorphologyUtils {

    /**
     * Parses a standard noun declension table from a list of forms.
     * Used by both German and French strategies.
     */
    fun parseNounDeclension(
        forms: JsonArray,
        categoryConfig: CategoryConfig?
    ): NounDeclensionTable {
        val nestedMap = mutableMapOf<String, MutableMap<String, String>>()

        forms.forEach { item ->
            val obj = item.jsonObject
            val form = obj[KEY_FORM]?.jsonPrimitive?.contentOrNull ?: return@forEach
            val tags = obj[KEY_TAGS]?.jsonArray?.mapNotNull { it.jsonPrimitive.contentOrNull } ?: emptyList()

            val case = tags.firstOrNull { it in listOf(NOMINATIVE, GENITIVE, DATIVE, ACCUSATIVE) }
            val number = tags.firstOrNull { it in listOf(SINGULAR, PLURAL) }

            if (case != null && number != null) {
                nestedMap.getOrPut(case) { mutableMapOf() }[number] = form
            }
        }

        val displayConfig = categoryConfig?.declension_display

        val cases = displayConfig?.cases_order ?: listOf(NOMINATIVE, GENITIVE, DATIVE, ACCUSATIVE)
        val numbers = displayConfig?.numbers_order ?: listOf(SINGULAR, PLURAL)

        val flatMap = mutableMapOf<Pair<String, String>, String>()
        cases.forEach { caseKey ->
            numbers.forEach { numberKey ->
                val form = nestedMap[caseKey]?.get(numberKey)
                if (form != null) {
                    flatMap[caseKey to numberKey] = form
                }
            }
        }

        return NounDeclensionTable(
            cases = cases,
            numbers = numbers,
            forms = flatMap
        )
    }

    /**
     * Checks if a JSON array contains noun-like structures (Case + Number).
     */
    fun isNounLikeStructure(forms: JsonArray, normalizedPos: String?): Boolean {
        if (forms.isEmpty()) return false

        val hasCaseAndNumber = forms.any { formElement ->
            val formObj = formElement.jsonObject
            val tags = formObj[KEY_TAGS]?.jsonArray?.mapNotNull { it.jsonPrimitive.contentOrNull } ?: emptyList()
            val hasCase = tags.any { it in listOf(NOMINATIVE, GENITIVE, DATIVE, ACCUSATIVE) }
            val hasNumber = tags.any { it in listOf(SINGULAR, PLURAL) }
            hasCase && hasNumber
        }

        return hasCaseAndNumber && (normalizedPos == null || normalizedPos.startsWith(GrammarConstants.POS_NOUN))
    }
}