from __future__ import annotations

import re
from typing import List


_SENTENCE_SPLIT_REGEX = re.compile(r"(?<=[.!?])\s+|(?<=[.!?])(?=[A-Za-z])")
_PARAGRAPH_SPLIT_REGEX = re.compile(r"\n\s*\n+")


def split_into_sentences(text: str) -> List[str]:
    if text is None:
        raise ValueError("text cannot be None")
    cleaned = text.strip()
    if not cleaned:
        return []
    return [sentence for sentence in _SENTENCE_SPLIT_REGEX.split(cleaned) if sentence]


def split_into_paragraphs(text: str) -> List[str]:
    if text is None:
        raise ValueError("text cannot be None")
    cleaned = text.strip()
    if not cleaned:
        return []
    paragraphs = _PARAGRAPH_SPLIT_REGEX.split(cleaned)
    return [_normalize_paragraph(paragraph) for paragraph in paragraphs if paragraph.strip()]


def chunk_facts(text: str, max_paragraphs_per_fact: int) -> List[str]:
    if text is None:
        raise ValueError("text cannot be None")
    cleaned = text.strip()
    if not cleaned:
        return []
    max_per_fact = max(1, int(max_paragraphs_per_fact))
    title, paragraphs = _extract_title_and_paragraphs(cleaned)
    if not paragraphs and title:
        paragraphs = [title]
    facts: List[str] = []
    current: List[str] = []
    for paragraph in paragraphs:
        if not paragraph:
            continue
        current.append(_prepend_title(paragraph, title))
        if len(current) >= max_per_fact:
            facts.append(" ".join(current).strip())
            current = []
    if current:
        facts.append(" ".join(current).strip())
    return facts


def _normalize_paragraph(paragraph: str) -> str:
    return " ".join(paragraph.strip().split())


def _extract_title_and_paragraphs(text: str) -> tuple[str | None, List[str]]:
    paragraphs = split_into_paragraphs(text)
    if len(paragraphs) < 2:
        return None, paragraphs
    first = paragraphs[0].strip()
    if not first:
        return None, paragraphs
    title = _detect_title(first)
    if title is None:
        return None, paragraphs
    return title, paragraphs[1:]


def _detect_title(text: str) -> str | None:
    cleaned = text.strip()
    if not cleaned:
        return None
    if cleaned.startswith("#"):
        return cleaned.lstrip("#").strip() or None
    lowered = cleaned.lower()
    if lowered.startswith("title:"):
        return cleaned.split(":", 1)[1].strip() or None
    if len(cleaned.split()) <= 10:
        return cleaned
    return None


def _prepend_title(paragraph: str, title: str | None) -> str:
    if not title:
        return paragraph
    paragraph_strip = paragraph.strip()
    if paragraph_strip.lower().startswith(title.lower()):
        return paragraph_strip
    return f"{title}. {paragraph_strip}".strip()
