"""모델용 고정 텍스트 투영의 scalar 줄 형식을 공유한다."""
from __future__ import annotations

import re


_CONTROL = re.compile(r"[\x00-\x09\x0b\x0c\x0e-\x1f\x7f-\x9f\u2028\u2029]")


def _one_line(text: str) -> str:
    """줄바꿈은 공백으로, 나머지 제어 문자는 `\\uXXXX` 로 바꿔 한 줄로 만든다."""
    text = text.replace("\n", " ").replace("\r", " ")
    return _CONTROL.sub(lambda match: f"\\u{ord(match.group(0)):04X}", text)


def scalar(value: object) -> str:
    """복합 값과 Markdown 줄 삽입을 노출하지 않는 scalar 문자열이다.

    `line` 이 이 값을 인라인 코드 span(백틱 한 쌍) 안에 넣으므로 값 안의 백틱은
    이스케이프한다. 백틱이 표기 그대로 남아야 하는 본문에는 `block` 을 쓴다.
    """
    if value is None or value == "" or not isinstance(value, (str, int, float, bool)):
        return "-"
    return _one_line(str(value).replace("`", "\\`"))


def block(text: str) -> str:
    """코드 span 밖에 놓이는 본문 한 덩어리의 투영이다.

    백틱은 그대로 둔다 — 본문의 백틱은 코드 표기이고, 이스케이프하면 번역자가 그
    백슬래시를 그대로 옮겨 렌더링에 남는다. 줄바꿈과 제어 문자 처리는 `scalar`
    와 같아서 본문이 다음 헤딩을 위조할 수 없다.
    """
    return _one_line(text)


def line(label: str, value: object) -> str:
    """한 scalar를 Markdown 목록 한 줄로 렌더한다."""
    if not re.fullmatch(r"[A-Za-z][A-Za-z0-9 ()/.-]*", label):
        raise ValueError("fixed text label must be a static single-line label")
    return f"- {label}: `{scalar(value)}`\n"


def value_lines(label: str, value: object) -> list[str]:
    """JSON 모양의 복합 값을 이름/순서/값 고정 줄로 손실 없이 펼친다."""
    if isinstance(value, dict):
        rows = [line(f"{label} field count", len(value))]
        for index, (name, child) in enumerate(value.items(), 1):
            rows.append(line(f"{label} field {index} name", name))
            rows.extend(value_lines(f"{label} field {index} value", child))
        return rows
    if isinstance(value, list):
        rows = [line(f"{label} item count", len(value))]
        for index, child in enumerate(value, 1):
            rows.extend(value_lines(f"{label} item {index}", child))
        return rows
    return [line(label, value)]
