@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.utils

import org.jsoup.Jsoup
import org.jsoup.nodes.Element

fun parseDefinitionsFromHtml(html: String, languageName: String? = null): List<String> {
    Log.d("HtmlParser", "parseDefinitionsFromHtml: htmlLength=${html.length}")
    val document = Jsoup.parse(html)
    val definitions = mutableListOf<String>()

    fun clean(text: String): String {
        var t = text.trim()
        // Remove bracketed references like [1]
        @Suppress("RegExpRedundantEscape")
        t = t.replace("\\s*\\[\\d+\\]".toRegex(), "").trim()
        // Remove obvious inline citation markers like "[2]", "[a]"
        @Suppress("RegExpRedundantEscape")
        t = t.replace("\\s*\\[[^]]+\\]".toRegex(), "").trim()
        // Remove edit bracket artifacts
        t = t.replace("\\s*¶".toRegex(), "").trim()
        // Collapse multiple spaces
        t = t.replace("\\s+".toRegex(), " ")
        return t
    }

    // Remove blocks that are not relevant to definitions globally (optional)
    document.select("div.interproject-box, table.audiotable, figure, div.NavFrame, div.navbox, style, link").remove()

    // Resolve language section robustly.
    // Prefer English if present, else take the first language header.
    // On Wiktionary, language headers can be:
    //  - h2#mylang (possibly wrapped in div.mw-heading2)
    //  - span.mw-headline#English (older markup)
    val target = languageName?.trim().takeUnless { it.isNullOrEmpty() }
    val lang = target ?: "English"
    val langId = lang.replace(" ", "_")
    val h2 = document.select("h2#$langId").firstOrNull()
    val span = document.select("span.mw-headline#$langId").firstOrNull()
    val anyH2 = document.select("h2[id]").firstOrNull()
    val anySpan = document.select("span.mw-headline[id]").firstOrNull()

    val languageHeader: Element? = h2 ?: span ?: anyH2 ?: anySpan

    if (languageHeader != null) {
        Log.d("HtmlParser", "Language header tag='${languageHeader.tagName()}', id='${languageHeader.id()}', text='${languageHeader.text()}'")
        val startFrom = languageHeader.parent()?.takeIf { it.hasClass("mw-heading") } ?: languageHeader
        var current: Element? = startFrom.nextElementSibling()

        val posCandidatesBase = listOf(
            "Noun", "Verb", "Adjective", "Adverb", "Pronoun", "Preposition",
            "Conjunction", "Interjection", "Determiner", "Article", "Proper noun"
        )
        // Heuristic: prioritize Proper noun for capitalized headwords
        val prioritized = listOf("Proper noun") + posCandidatesBase.filter { it != "Proper noun" }
        var foundPos = false

        fun elementIsLanguageBoundary(el: Element): Boolean {
            if (el.tagName() == "h2") return true
            if (el.hasClass("mw-heading") && el.selectFirst("h2") != null) return true
            return false
        }

        fun findFirstOlAfter(nodeStart: Element?): Element? {
            var node = nodeStart
            var steps = 0
            while (node != null && steps < 20) {
                val h3 = if (node.tagName() == "h3") node else node.selectFirst("h3")
                if (h3 != null && h3 != nodeStart) break
                if (elementIsLanguageBoundary(node)) break
                if (node.tagName() == "ol") return node
                node = node.nextElementSibling()
                steps++
            }
            return null
        }

        fun extractDefinitionFromLi(li: Element): String {
            // Clone and remove non-essential nested blocks but keep inline text
            val copy = li.clone()
            // Remove nested lists (examples, subsenses), tables, figures, dl/dd quotes, references
            copy.select("ul, ol, table, figure, div.NavFrame, dl, blockquote").remove()
            copy.select("sup.reference, sup, span.citation, span.ref, span.mwe-math-element").remove()
            // Now get full text including inline anchors/spans
            val raw = copy.text()
            return clean(raw)
        }

        while (current != null) {
            if (elementIsLanguageBoundary(current)) break

            val h3 = if (current.tagName() == "h3") current else current.selectFirst("h3")
            val headerText = (h3?.text() ?: current.select("span.mw-headline").firstOrNull()?.text()).orEmpty()
            if (headerText.isNotEmpty() && prioritized.any { headerText.contains(it, ignoreCase = true) }) {
                if (!foundPos) Log.d("HtmlParser", "POS header '$headerText' found; extracting definitions")
                foundPos = true
                val listEl = findFirstOlAfter(current.nextElementSibling() ?: current)
                var count = 0
                listEl?.children()?.forEach { li ->
                    if (li.tagName() == "li") {
                        val text = extractDefinitionFromLi(li)
                        if (text.isNotBlank()) {
                            definitions.add(text)
                            count++
                        }
                    }
                }
                Log.d("HtmlParser", "Collected $count definitions under '$headerText'")
                if (definitions.isNotEmpty()) break
            }
            current = current.nextElementSibling()
        }
    } else {
        Log.w("HtmlParser", "No language headers found; definitions likely empty")
    }
    Log.d("HtmlParser", "Returning ${definitions.size} definitions")
    return definitions
}