"""Shared text processing utilities for OCR and subtitle matching.

These utilities are framework-agnostic and don't depend on heavy ML libraries (easyocr, torch).
They can be safely imported across the codebase without triggering heavy dependency imports.
"""

import logging
import re
import unicodedata
from typing import List, Optional

import nltk
import wordninja
from langdetect import detect, LangDetectException
from nltk.corpus import stopwords

logger = logging.getLogger(__name__)

try:
    nltk.data.find("corpora/stopwords.zip")
except LookupError:
    nltk.download("stopwords", quiet=True)

try:
    nltk.data.find("tokenizers/punkt")
except LookupError:
    nltk.download("punkt", quiet=True)

SUPPORTED_LANGUAGES = {
    "fr": set(stopwords.words("french")),
    "en": set(stopwords.words("english")),
    "de": set(stopwords.words("german")),
    "es": set(stopwords.words("spanish")),
    "it": set(stopwords.words("italian")),
}


def normalize_text(text: str) -> str:
    """
    Normalize input text for OCR processing.

    Converts to lowercase, removes diacritics (accents), strips punctuation
    and special characters.

    Args:
        text: The input string to normalize

    Returns:
        Normalized, lowercase string with only alphanumeric characters and spaces
    """
    text = text.lower()
    text = unicodedata.normalize("NFD", text)
    text = "".join(c for c in text if unicodedata.category(c) != "Mn")
    text = re.sub(r"['']", "", text)
    text = re.sub(r"[^a-z0-9\s]", " ", text)
    return text


def clean_and_tokenize(text: str) -> List[str]:
    """
    Normalize and split text into word tokens.

    Args:
        text: The input string to process

    Returns:
        List of lowercase word tokens
    """
    return re.findall(r"\w+", normalize_text(text))


def fix_suspicious_tokens(tokens: List[str]) -> List[str]:
    """
    Fix over-merged or suspiciously long OCR tokens using wordninja.

    Splits any token longer than 12 characters into more likely component words.

    Args:
        tokens: List of raw string tokens

    Returns:
        List of improved and more natural tokens
    """
    fixed = []
    for token in tokens:
        if len(token) > 12:
            fixed.extend(wordninja.split(token))
        else:
            fixed.append(token)
    return fixed


def filter_ocr_tokens(tokens: List[str], lang: str) -> List[str]:
    """
    Filter tokens by removing short words, non-alphabetic characters, and stopwords.

    Args:
        tokens: List of token strings
        lang: ISO language code

    Returns:
        Filtered token list
    """
    lang = lang.lower()
    if lang not in SUPPORTED_LANGUAGES:
        logger.warning(
            f"Unsupported language for stopwords: '{lang}'. Skipping stopword filtering."
        )
        return [t for t in tokens if len(t) > 2 and t.isalpha()]

    stop_words = SUPPORTED_LANGUAGES[lang]
    return [t for t in tokens if len(t) > 2 and t.isalpha() and t not in stop_words]


def detect_language(text: str) -> Optional[str]:
    """
    Detect language from text using langdetect.

    Args:
        text: Text to analyze

    Returns:
        ISO language code (e.g., 'en', 'fr') or None if detection fails
    """
    if not text or len(text.strip()) < 10:
        return None

    try:
        return detect(text)
    except LangDetectException:
        logger.warning("Language detection failed for text")
        return None
