@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.model.grammar

import android.content.Context
import eu.gaudian.translator.R
import eu.gaudian.translator.model.grammar.GrammarConstants.POS_ADJ
import eu.gaudian.translator.model.grammar.GrammarConstants.POS_NOUN
import eu.gaudian.translator.model.grammar.GrammarConstants.POS_VERB
import eu.gaudian.translator.utils.Log

object UnifiedMorphologyParser {

    private const val TAG = "UnifiedMorphologyParser"

    fun parse(
        entry: DictionaryEntryData,
        lemma: String,
        pos: String?,
        langCode: String,
        config: LanguageConfig,
        context: Context
    ): UnifiedMorphology? {
        // 1. Log Input
        Log.d(TAG, "Request: lemma='$lemma', lang='$langCode', pos='$pos'")

        if (entry.forms.isEmpty()) {
            Log.d(TAG, "Aborting: No forms data available for '$lemma'")
            return null
        }

        // FIX 1: Normalize POS tags (map "adj" -> "adjective", etc.)
        val normalizedPos = normalizePos(pos)

        if (normalizedPos == null) {
            Log.w(TAG, "Aborting: POS could not be normalized for '$lemma' (raw: $pos)")
            return null
        }

        // 2. Determine Rule Source
        // First, check JSON Config
        var rule = buildRuleFromConfig(normalizedPos, config, context)
        val ruleSource = if (rule != null) "JSON Config" else "Registry Fallback"

        // If not in JSON, check Registry
        if (rule == null) {
            rule = MorphologyRegistry.getRule(langCode, normalizedPos)
        }

        Log.d(TAG, "Strategy: Using $ruleSource for $langCode|$normalizedPos")

        // 3. Execute Extraction
        val result = try {
            when (rule) {
                is MorphologyRule.GridRule -> {
                    Log.d(TAG, "Extracting Grid: ${rule.title}")
                    parseGrid(entry.forms, rule, lemma)
                }
                is MorphologyRule.VerbRule -> {
                    Log.d(TAG, "Extracting Verb Paradigm")
                    parseVerb(entry.forms, rule, lemma)
                }
                is MorphologyRule.GenericRule -> {
                    Log.d(TAG, "Extracting Generic List")
                    parseGeneric(entry.forms)
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error extracting morphology for '$lemma': ${e.message}")
            return null
        }

        // 4. Log Outcome
        if (result != null) {
            Log.d(TAG, "Success: Generated ${result::class.java.simpleName} for '$lemma'")
        } else {
            Log.w(TAG, "Result was null for '$lemma'")
        }

        return result
    }

    /**
     * Maps short/raw POS tags to the standard GrammarConstants keys.
     */
    private fun normalizePos(pos: String?): String? {
        val raw = pos?.lowercase()?.trim() ?: return null
        return when (raw) {
            "adj", "adjective", "adjectif" -> POS_ADJ // "adjective"
            "noun", "substantive", "nom" -> POS_NOUN  // "noun"
            "verb", "verbe" -> POS_VERB               // "verb"
            else -> raw // Return as-is if no map found (e.g. "adverb")
        }
    }

    private fun buildRuleFromConfig(pos: String, config: LanguageConfig, context: Context): MorphologyRule? {
        val category = config.categories[pos] ?: return null
        return when (pos) {
            // MERGED: Nouns AND Adjectives both use Grid Logic
            POS_NOUN, POS_ADJ -> {
                val display = category.declension_display ?: return null
                if (display.cases_order != null && display.numbers_order != null) {

                    // FIX 2: Define a fallback strategy for Adjectives.
                    // If a cell is missing (e.g. Masc/Sing), use the lemma.
                    val fallback: ((String, String, String) -> String?)? = if (pos == POS_ADJ) {
                        { row, col, lemma ->
                            // If looking for Masculine Singular, assume it's the Lemma
                            if (row.startsWith("masc") && col.startsWith("sing")) lemma else null
                        }
                    } else null

                    MorphologyRule.GridRule(
                        title = if (pos == POS_ADJ) context.getString(R.string.label_variations) else context.getString(R.string.label_declension),
                        rowTags = display.cases_order,
                        colTags = display.numbers_order,
                        fallbackStrategy = fallback
                    )
                } else null
            }
            POS_VERB -> {
                val display = category.conjugation_display ?: return null
                if (display.tense_labels != null && display.pronouns != null) {
                    MorphologyRule.VerbRule(
                        tenses = display.tense_labels,
                        pronouns = display.pronouns
                    )
                } else null
            }
            else -> null
        }
    }

    // --- EXECUTION LOGIC ---

    private fun parseGrid(
        forms: List<FormData>,
        rule: MorphologyRule.GridRule,
        lemma: String
    ): UnifiedMorphology.Grid {
        val cells = mutableMapOf<String, String>()

        // Optimization: Lookup map
        val formLookup = forms.associate { formData ->
            formData.tags.map { it.lowercase() }.toSet() to formData.form
        }

        rule.rowTags.forEach { rowTag ->
            rule.colTags.forEach { colTag ->
                val requiredTags = listOf(rowTag, colTag)
                    .filter { it.isNotEmpty() }
                    .map { it.lowercase() }

                val matchEntry = formLookup.entries.find { (tags, _) ->
                    tags.containsAll(requiredTags)
                }

                // Try to get value from match, OR use fallback (Lemma)
                val cellValue = matchEntry?.value
                    ?: rule.fallbackStrategy?.invoke(rowTag, colTag, lemma)

                if (cellValue != null) {
                    val key = if (colTag.isEmpty()) rowTag else "$rowTag|$colTag"
                    cells[key] = cellValue
                }
            }
        }

        return UnifiedMorphology.Grid(
            title = rule.title,
            rowLabels = rule.rowTags,
            colLabels = rule.colTags.filter { it.isNotEmpty() },
            cells = cells
        )
    }

    private fun parseVerb(
        forms: List<FormData>,
        rule: MorphologyRule.VerbRule,
        lemma: String
    ): UnifiedMorphology.Verb {
        val tenseResults = mutableMapOf<String, List<String>>()

        rule.tenses.forEach { (tenseKey, displayLabel) ->
            val relevantForms = forms.filter { form ->
                form.tags.any { tag -> tag.equals(tenseKey, ignoreCase = true) }
            }

            if (relevantForms.isNotEmpty()) {
                val truncated = relevantForms.take(rule.pronouns.size).map { it.form }
                tenseResults[displayLabel] = truncated
            }
        }

        val aux = forms.find { it.tags.contains("auxiliary") }?.form

        return UnifiedMorphology.Verb(
            infinitive = lemma,
            auxiliary = aux,
            tenses = tenseResults,
            pronouns = rule.pronouns
        )
    }

    private fun parseGeneric(forms: List<FormData>): UnifiedMorphology.ListForms {
        return UnifiedMorphology.ListForms(
            forms.map { Inflection(it.form, it.tags) }
        )
    }
}