"""Shared deterministic reviewed-document chunk contract for FTS and read APIs."""

from __future__ import annotations

import re
from dataclasses import dataclass
from typing import Iterator

CHUNK_CHARS = 1400
MAX_CHUNK_CHARS = 1400


@dataclass(frozen=True)
class DocumentChunk:
    """A stable, one-based section within normalized document text."""

    number: int
    text: str


def normalize_document_text(value: object) -> str:
    """Normalize line endings and blank lines without altering searchable content."""
    text = str(value or "").replace("\r\n", "\n").replace("\r", "\n")
    return "\n".join(line.strip() for line in text.split("\n") if line.strip())


def iter_document_chunks(value: object) -> Iterator[DocumentChunk]:
    """Yield stable chunks; never silently cap total document content."""
    text = normalize_document_text(value)
    if not text:
        return
    for offset in range(0, len(text), CHUNK_CHARS):
        yield DocumentChunk(
            number=(offset // CHUNK_CHARS) + 1, text=text[offset : offset + CHUNK_CHARS]
        )


def document_chunks(value: object) -> list[DocumentChunk]:
    return list(iter_document_chunks(value))


def encode_chunk_cursor(number: int) -> str:
    if not isinstance(number, int) or number < 1:
        raise ValueError("invalid chunk cursor")
    return f"section-{number}"


def decode_chunk_cursor(value: str) -> int:
    match = re.fullmatch(r"section-([1-9][0-9]{0,5})", value)
    if not match:
        raise ValueError("invalid chunk cursor")
    return int(match.group(1))
