import html
import re


def to_html(obj):

    return html.escape(str(obj))


def format_llm_answer_html(text: str | None) -> str:
    if text is None:
        return ""

    escaped = html.escape(str(text).replace("\r\n", "\n").strip())
    normalized_lines = []

    for line in escaped.split("\n"):
        normalized_line = re.sub(r"^\s*[-*]\s+", "• ", line.rstrip())
        normalized_lines.append(normalized_line)

    formatted = "\n".join(normalized_lines)
    formatted = re.sub(r"\*\*(.+?)\*\*", r"<b>\1</b>", formatted)
    return formatted


def split_plain_text_chunks(text: str | None, limit: int = 3500) -> list[str]:
    if text is None:
        return [""]

    normalized = str(text).replace("\r\n", "\n").strip()
    if not normalized:
        return [""]

    paragraphs = normalized.split("\n\n")
    chunks: list[str] = []
    current = ""

    for paragraph in paragraphs:
        paragraph = paragraph.strip()
        if not paragraph:
            continue

        candidate = paragraph if not current else f"{current}\n\n{paragraph}"
        if len(candidate) <= limit:
            current = candidate
            continue

        if current:
            chunks.append(current)
            current = ""

        if len(paragraph) <= limit:
            current = paragraph
            continue

        lines = paragraph.split("\n")
        line_buffer = ""

        for line in lines:
            line = line.rstrip()
            line_candidate = line if not line_buffer else f"{line_buffer}\n{line}"
            if len(line_candidate) <= limit:
                line_buffer = line_candidate
                continue

            if line_buffer:
                chunks.append(line_buffer)
                line_buffer = ""

            while len(line) > limit:
                chunks.append(line[:limit].rstrip())
                line = line[limit:].lstrip()

            line_buffer = line

        if line_buffer:
            current = line_buffer

    if current:
        chunks.append(current)

    return chunks or [normalized[:limit]]


def parse_links_to_inline_markup(message: str) -> list:
    """
    Парсит сообщение с форматированными ссылками и возвращает список рядов кнопок.

    Формат входного сообщения:
    - [Текст кнопки + Ссылка] для одной кнопки.
    - [Кнопка1 + Ссылка1][Кнопка2 + Ссылка2] для нескольких кнопок в одном ряду.
    - Каждая строка представляет отдельный ряд кнопок.

    Пример:
    [Кнопка1 + https://example.com]
    [Кнопка2 + https://example.org][Кнопка3 + https://example.net]

    :param message: Строка с отформатированными ссылками.
    :return: Список рядов кнопок, где каждый ряд — это список кортежей (Текст, Ссылка).
    """
    # Исправленное регулярное выражение для поиска [Текст + Ссылка]
    pattern = re.compile(r"\[([^\[\]+]+)\s*\+\s*(https?://[^\[\]]+)\]")

    # Инициализируем список рядов кнопок
    keyboard_rows = []

    # Разбиваем сообщение на строки
    lines = message.strip().split("\n")

    for line in lines:
        # Находим все совпадения в строке
        matches = pattern.findall(line)
        if matches:
            row = []
            for text, url in matches:
                button = (text.strip(), url.strip())
                row.append(button)
            keyboard_rows.append(row)

    return keyboard_rows
