"""
Утилиты для обработки и нормализации текста.
Используется для обнаружения спама и обхода фильтров.

Pipeline обработки текста:
1. unicode_to_ascii() - замена Unicode-символов
2. normalize_text() - латиница → кириллица, удаление диакритики
3. clean_separators() - удаление разделителей ("г е й" → "гей")
4. get_lemma() - получение нормальной формы слова
"""
import re
import unicodedata
from typing import Set, List
from pymorphy3 import MorphAnalyzer

from configs.mapping import UNICODE_MAP, LATIN_TO_CYRILLIC, CYRILLIC_NORMALIZE

__all__ = (
    "unicode_to_ascii",
    "normalize_text",
    "clean_separators",
    "process_text",
    "get_lemma",
    "get_inflected_forms",
    "morph",
    "extract_words"
)

# Глобальный экземпляр морфоанализатора (инициализируется один раз)
morph = MorphAnalyzer()


def unicode_to_ascii(text: str) -> str:
    """
    Преобразует Unicode-символы в ASCII/кириллические аналоги.

    Args:
        text: Текст с Unicode-символами

    Returns:
        str: Текст с нормализованными символами

    Examples:
        >> unicode_to_ascii("ｐｒｉｖｅｔ")
        "привет"
        >> unicode_to_ascii("κупиτь")
        "купить"
        >> unicode_to_ascii("𝐡𝐞𝐥𝐥𝐨")
        "нелло"
    """
    return ''.join(UNICODE_MAP.get(char, char) for char in text)


def normalize_text(text: str) -> str:
    """
    Нормализует текст для обхода фильтров:
    1. Удаляет диакритические знаки (é → e, ė → e)
    2. Заменяет латинские буквы на кириллические
    3. Заменяет похожие кириллические буквы (укр/бел) на русские

    Args:
        text: Исходный текст

    Returns:
        str: Нормализованный текст

    Examples:
        >> normalize_text("prívét")
        "привет"
        >> normalize_text("hеllo")  # h - кириллическая
        "нелло"
        >> normalize_text("Київ")  # і → и
        "Киев"
    """
    # Шаг 1: Удаляем диакритические знаки (акценты)
    # NFD разбивает символ на базовый + диакритику
    text = unicodedata.normalize('NFD', text)
    # Mn = Mark, Nonspacing (диакритические знаки)
    text = ''.join(char for char in text if unicodedata.category(char) != 'Mn')
    # Возвращаем в NFC (композитная форма)
    text = unicodedata.normalize('NFC', text)

    # Шаг 2: Заменяем латинские → кириллица и нормализуем кириллицу
    result: List[str] = []
    for char in text:
        # Сначала латиница → кириллица
        if char in LATIN_TO_CYRILLIC:
            result.append(LATIN_TO_CYRILLIC[char])
        # Потом нормализуем кириллицу (укр/бел → рус)
        elif char in CYRILLIC_NORMALIZE:
            result.append(CYRILLIC_NORMALIZE[char])
        else:
            result.append(char)

    return ''.join(result)


def clean_separators(text: str) -> str:
    """
    Удаляет разделители между буквами для обнаружения обхода через пробелы/символы.

    Args:
        text: Исходный текст

    Returns:
        str: Текст без разделителей между буквами

    Examples:
        >> clean_separators("г е й")
        "гей"
        >> clean_separators("г.е.й")
        "гей"
        >> clean_separators("г*е*й")
        "гей"
        >> clean_separators("к у п и т ь")
        "купить"
        >> clean_separators("нормальный текст тут")
        "нормальный текст тут"
    """
    # Удаляем все НЕ буквенно-цифровые символы, кроме пробелов
    cleaned: str = re.sub(r'[^\w\s]', '', text, flags=re.UNICODE)

    # Убираем множественные пробелы
    cleaned = re.sub(r'\s+', ' ', cleaned)

    # Убираем пробелы между отдельными буквами
    # "г е й" → "гей", но "нормальный текст" остаётся
    words = cleaned.split()
    result: List[str] = []
    temp_chars: List[str] = []

    for word in words:
        if len(word) == 1:
            # Одиночный символ - копим
            temp_chars.append(word)
        else:
            # Полное слово - сначала сбрасываем накопленные символы
            if temp_chars:
                result.append(''.join(temp_chars))
                temp_chars = []
            result.append(word)

    # Не забываем остаток
    if temp_chars:
        result.append(''.join(temp_chars))

    return ' '.join(result)


def process_text(text: str, remove_spaces: bool = False) -> str:
    """
    Полный пайплайн обработки текста для спам-фильтра.

    Args:
        text: Исходный текст
        remove_spaces: Удалить все пробелы (для проверки part-слов)

    Returns:
        str: Обработанный текст в нижнем регистре

    Examples:
        >> process_text("Κупи*τь сейчас!")
        "купить сейчас"
        >> process_text("г е й", remove_spaces=True)
        "гей"
    """
    # Приводим к нижнему регистру
    text = text.casefold()

    # Шаг 1: Unicode → ASCII/кириллица
    text = unicode_to_ascii(text)

    # Шаг 2: Нормализация (латиница → кириллица, диакритика)
    text = normalize_text(text)

    # Шаг 3: Удаление разделителей
    text = clean_separators(text)

    # Опционально: удаляем все пробелы (для part-проверки)
    if remove_spaces:
        text = re.sub(r'\s+', '', text)

    return text


def get_lemma(word: str) -> str:
    """
    Получает нормальную форму слова (лемму).

    Args:
        word: Слово для анализа

    Returns:
        str: Лемма (нормальная форма)

    Examples:
        >> get_lemma("купил")
        "купить"
        >> get_lemma("карты")
        "карта"
        >> get_lemma("хочется")
        "хотеться"
    """
    try:
        parsed = morph.parse(word)[0]
        return parsed.normal_form
    except (IndexError, Exception):
        return word


def get_inflected_forms(base_word: str, limit: int = 50) -> Set[str]:
    """
    Получает все словоформы слова через морфологический анализ.

    Args:
        base_word: Исходное слово
        limit: Максимальное количество форм (для экономии памяти)

    Returns:
        Set[str]: Набор всех словоформ (падежи, числа и т.д.)

    Examples:
        >> get_inflected_forms("купить")
        {'купить', 'куплю', 'купишь', 'купит', ...}
        >> get_inflected_forms("карта")
        {'карта', 'карты', 'карте', 'карту', ...}
    """
    try:
        parsed = morph.parse(base_word)[0]
        forms: Set[str] = set()

        for form in parsed.lexeme:
            if len(forms) >= limit:
                break
            forms.add(form.normal_form)
            forms.add(form.word)

        return forms
    except Exception:
        return {base_word}


def extract_words(text: str) -> List[str]:
    """
    Извлекает слова из текста (только буквы).

    Args:
        text: Текст для обработки

    Returns:
        List[str]: Список слов

    Examples:
        >> extract_words("Привет, как дела?")
        ['Привет', 'как', 'дела']
    """
    return re.findall(r'\b\w+\b', text, flags=re.UNICODE)


def calculate_similarity(text1: str, text2: str) -> float:
    """
    Вычисляет схожесть двух текстов (простая метрика).

    Args:
        text1: Первый текст
        text2: Второй текст

    Returns:
        float: Коэффициент схожести (0.0 - 1.0)

    Examples:
        >> calculate_similarity("привет", "привет")
        1.0
        >> calculate_similarity("купить", "продать")
        0.0
    """
    processed1 = process_text(text1)
    processed2 = process_text(text2)

    if processed1 == processed2:
        return 1.0

    # Levenshtein distance (простой вариант)
    len1, len2 = len(processed1), len(processed2)
    if len1 == 0 or len2 == 0:
        return 0.0

    # Считаем совпадающие символы
    matches = sum(1 for a, b in zip(processed1, processed2) if a == b)
    return matches / max(len1, len2)
