@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.model.grammar

/**
 * Parser for extracting adjective variations from raw forms data.
 * 
 * This class is responsible for parsing FormData into structured AdjectiveVariation
 * objects that can be easily displayed in the UI. It separates the parsing logic
 * from the UI components for better testability and maintainability.
 */
object AdjectiveVariationsParser {

    /**
     * Supported languages for adjective variations.
     */
    private val SUPPORTED_LANGUAGES = setOf("fr", "pt", "de")

    /**
     * Gender tags that we recognize.
     */
    private val GENDER_TAGS = setOf("masculine", "feminine", "neuter")

    /**
     * Number tags that we recognize.
     */
    private val NUMBER_TAGS = setOf("singular", "plural")

    /**
     * Standard gender-number combinations to display in the table.
     */
    private val STANDARD_COMBINATIONS = listOf(
        GenderNumberCombination("masculine", "singular"),
        GenderNumberCombination("masculine", "plural"),
        GenderNumberCombination("feminine", "singular"),
        GenderNumberCombination("feminine", "plural")
    )

    /**
     * Data class representing a gender-number combination.
     */
    data class GenderNumberCombination(
        val gender: String,
        val number: String
    )

    /**
     * Parsed adjective variation ready for UI display.
     */
    data class ParsedAdjectiveVariation(
        val form: String,
        val gender: String,
        val number: String,
        val tags: List<String>,
        val ipas: List<String>
    )

    /**
     * Result of parsing adjective variations.
     */
    data class AdjectiveVariationsResult(
        val variations: List<ParsedAdjectiveVariation>,
        val hasCompleteData: Boolean // Whether all 4 standard combinations are present
    )

    /**
     * Check if the given language and forms data represents an adjective with variations.
     * 
     * @param langCode Language code (e.g., "fr", "pt", "de")
     * @param pos Part of speech (optional)
     * @param forms List of FormData from the dictionary entry
     * @return true if this appears to be an adjective with variations
     */
    fun isAdjectiveWithVariations(
        langCode: String,
        pos: String?,
        forms: List<FormData>
    ): Boolean {
        if (langCode !in SUPPORTED_LANGUAGES || forms.isEmpty()) {
            return false
        }

        // Check if POS explicitly indicates adjective
        val isAdjectiveByPos = pos?.equals("adjective", ignoreCase = true) == true
        if (isAdjectiveByPos) {
            return true
        }

        // Check if forms contain gender and number tags (indicating adjective variations)
        return hasGenderNumberTags(forms)
    }

    /**
     * Parse adjective variations from forms data.
     * 
     * @param forms List of FormData from the dictionary entry
     * @param lemma The base form of the adjective (used as fallback for missing combinations)
     * @return AdjectiveVariationsResult containing parsed variations
     */
    fun parseVariations(
        forms: List<FormData>,
        lemma: String? = null
    ): AdjectiveVariationsResult {
        val variations = mutableListOf<ParsedAdjectiveVariation>()

        // Parse each standard combination
        STANDARD_COMBINATIONS.forEach { combination ->
            val form = findFormForCombination(forms, combination)
            if (form != null) {
                variations.add(ParsedAdjectiveVariation(
                    form = form.form,
                    gender = combination.gender,
                    number = combination.number,
                    tags = form.tags,
                    ipas = form.ipas
                ))
            } else if (lemma != null && combination.gender == "masculine" && combination.number == "singular") {
                // Use lemma as fallback for masculine singular
                variations.add(ParsedAdjectiveVariation(
                    form = lemma,
                    gender = combination.gender,
                    number = combination.number,
                    tags = listOf("masculine", "singular"),
                    ipas = emptyList()
                ))
            }
        }

        val hasCompleteData = variations.size == STANDARD_COMBINATIONS.size

        return AdjectiveVariationsResult(
            variations = variations,
            hasCompleteData = hasCompleteData
        )
    }

    /**
     * Get display labels for the supported languages.
     */
    fun getLanguageDisplayLabels(langCode: String): Map<String, String> {
        return when (langCode) {
            "fr" -> mapOf(
                "masculine" to "Masculin",
                "feminine" to "Féminin",
                "singular" to "Singulier",
                "plural" to "Pluriel"
            )
            "pt" -> mapOf(
                "masculine" to "Masculino",
                "feminine" to "Feminino",
                "singular" to "Singular",
                "plural" to "Plural"
            )
            "de" -> mapOf(
                "masculine" to "Maskulin",
                "feminine" to "Feminin",
                "neuter" to "Neutrum",
                "singular" to "Singular",
                "plural" to "Plural"
            )
            else -> mapOf(
                "masculine" to "Masculine",
                "feminine" to "Feminine",
                "neuter" to "Neuter",
                "singular" to "Singular",
                "plural" to "Plural"
            )
        }
    }

    /**
     * Check if forms contain gender and number tags.
     */
    private fun hasGenderNumberTags(forms: List<FormData>): Boolean {
        return forms.any { formData ->
            val tags = formData.tags.map { it.lowercase() }
            val hasGender = tags.any { it in GENDER_TAGS }
            val hasNumber = tags.any { it in NUMBER_TAGS }
            hasGender && hasNumber
        }
    }

    /**
     * Find the form that matches a specific gender-number combination.
     */
    private fun findFormForCombination(
        forms: List<FormData>,
        combination: GenderNumberCombination
    ): FormData? {
        return forms.find { formData ->
            val tags = formData.tags.map { it.lowercase() }
            tags.contains(combination.gender) && tags.contains(combination.number)
        }
    }
}
