from __future__ import annotations

import re

_VERB_MARKERS = (
    " is ",
    " was ",
    " were ",
    " are ",
    " has ",
)


def format_raw_output(facts: str, background: str) -> str:
    facts_lines = _normalize_lines(facts)
    background_lines = _normalize_lines(background)
    combined = facts_lines
    if background_lines:
        combined = facts_lines + [""] + background_lines
    resolved_lines = _apply_pronoun_substitution(combined)
    return "\n".join(resolved_lines).strip()


def _normalize_lines(text: str) -> list[str]:
    if not text:
        return []
    lines = []
    for raw in text.splitlines():
        cleaned = _strip_numbering(raw)
        if cleaned:
            lines.append(cleaned)
    return lines


def _strip_numbering(text: str) -> str:
    cleaned = text.strip()
    if not cleaned:
        return ""
    match = re.match(r"^\d+\)\s+(.*)$", cleaned)
    if match:
        return match.group(1).strip()
    return cleaned


def _apply_pronoun_substitution(lines: list[str]) -> list[str]:
    last_entity = None
    last_pronoun = None
    output: list[str] = []
    for line in lines:
        if not line:
            output.append("")
            continue
        entity = _extract_leading_entity(line)
        if entity and last_entity and entity.casefold() == last_entity.casefold():
            pronoun = last_pronoun or _choose_pronoun(entity)
            output.append(_replace_leading_entity(line, entity, pronoun))
        else:
            output.append(line)
            if entity:
                last_entity = entity
                last_pronoun = _choose_pronoun(entity)
    return output


def _extract_leading_entity(line: str) -> str | None:
    trimmed = line.strip()
    if not trimmed:
        return None
    lower = trimmed.lower()
    boundary = None
    for marker in _VERB_MARKERS:
        idx = lower.find(marker)
        if idx != -1:
            boundary = idx
            break
    if boundary is None:
        return None
    candidate = trimmed[:boundary].strip(" ,.;:-")
    if not candidate or len(candidate) > 80:
        return None
    return candidate


def _replace_leading_entity(line: str, entity: str, pronoun: str) -> str:
    if line.startswith(entity):
        return f"{pronoun}{line[len(entity):]}"
    lowered = line.lower()
    lowered_entity = entity.lower()
    if lowered.startswith(lowered_entity):
        return f"{pronoun}{line[len(entity):]}"
    return line


def _choose_pronoun(entity: str) -> str:
    tokens = [token for token in entity.split() if token]
    if len(tokens) >= 2 and tokens[0][0].isupper():
        return "he"
    return "it"
