"""
Verbatim content extraction.

Generic article extractors are tuned for prose: they strip short lines,
repeated structures and anything that looks like navigation. That behaviour
destroys exactly the content users most often want reproduced word-for-word —
song lyrics, poems, recipe ingredient lists, code blocks, transcripts.

This module pulls that content out of the page structure directly, before the
prose extractor gets a chance to discard it.
"""
from __future__ import annotations

import re
from typing import List, Optional, Tuple

from selectolax.parser import HTMLParser

# Ordered: the most specific container wins.
CONTENT_SELECTORS: Tuple[Tuple[str, str], ...] = (
    # lyrics
    ('div[data-lyrics-container="true"]', "lyrics"),
    ('div[class^="Lyrics__Container"]', "lyrics"),
    ("#lyrics-root", "lyrics"),
    ("div.lyricbox", "lyrics"),
    ("div.lyrics", "lyrics"),
    ("pre.lyric-body", "lyrics"),
    ("div#lyric-body-text", "lyrics"),
    ("div.songLyricsV14", "lyrics"),
    ("div.ringtone ~ div", "lyrics"),
    # recipes
    ("ul.mm-recipes-structured-ingredients__list", "recipe"),
    ('[itemprop="recipeInstructions"]', "recipe"),
    ('[itemprop="recipeIngredient"]', "recipe"),
    ("div.recipe-ingredients", "recipe"),
    # transcripts / subtitles
    ("div.transcript", "transcript"),
    ("div.post-content", "transcript"),
    # poems
    ("div.poem", "poem"),
    ("div.o-poem", "poem"),
)

_JUNK_LINE = re.compile(
    r"^(?:\d+\s+Contributors?|Translations?|Read More|Share|Embed|"
    r"You might also like|See .* Live|Get tickets|Advertisement|"
    r"Sign ?up|Log ?in|Subscribe)\b",
    re.I,
)

_LANG_NOISE = {
    "deutsch", "türkçe", "español", "português", "français", "italiano",
    "polski", "русский", "українська", "中文", "日本語", "한국어", "עברית",
    "العربية", "فارسی", "ไทย (thai)", "nederlands", "svenska", "suomi",
    "magyar", "čeština", "română", "ελληνικά", "srpski", "hrvatski",
    "български", "tiếng việt", "bahasa indonesia", "filipino", "azərbaycanca",
}


def _clean_block(text: str) -> str:
    """Drop UI chrome while preserving line structure and blank lines."""
    out: List[str] = []
    for raw in (text or "").split("\n"):
        line = raw.rstrip()
        low = line.strip().lower()
        if not line.strip():
            if out and out[-1] != "":
                out.append("")
            continue
        if _JUNK_LINE.match(line.strip()):
            continue
        if low in _LANG_NOISE:
            continue
        out.append(line)
    # trim leading/trailing blanks
    while out and out[0] == "":
        out.pop(0)
    while out and out[-1] == "":
        out.pop()
    return "\n".join(out)


def extract_verbatim(html: str) -> Optional[Tuple[str, str]]:
    """
    Return (text, kind) when the page exposes a verbatim-content container.

    None means no structured container was found and the caller should fall
    back to normal article extraction.
    """
    if not html:
        return None
    try:
        tree = HTMLParser(html)
    except Exception:
        return None

    for selector, kind in CONTENT_SELECTORS:
        try:
            nodes = tree.css(selector)
        except Exception:
            continue
        if not nodes:
            continue
        parts = []
        for n in nodes:
            # <br> separated lyrics need newline separators to survive
            txt = n.text(separator="\n", strip=False)
            if txt and txt.strip():
                parts.append(txt)
        if not parts:
            continue
        text = _clean_block("\n\n".join(parts))
        # A real lyrics/recipe block has multiple short lines; a stray match
        # on a nav container will not.
        lines = [l for l in text.split("\n") if l.strip()]
        if len(text) >= 200 and len(lines) >= 6:
            return text, kind
    return None
