"""占位符核心：支持 <<key>>、{{key}}、((key))、《key》 等多种包裹形式。"""
from __future__ import annotations

import re
from dataclasses import dataclass, field

# 多种占位符形式（可按需扩展），键允许中文、字母、数字、下划线、点、短横线等
_PATTERNS = (
    r"<<\s*(?P<p1>.+?)\s*>>",
    r"\{\{\s*(?P<p2>.+?)\s*\}\}",
    r"\(\(\s*(?P<p3>.+?)\s*\)\)",
    r"《\s*(?P<p4>.+?)\s*》",
    r"【\s*(?P<p5>.+?)\s*】",
)
_PLACEHOLDER_RE = re.compile("|".join(_PATTERNS))


@dataclass
class RenderResult:
    rendered: str
    unresolved: list[str] = field(default_factory=list)
    replacements: int = 0


def _normalize_key(key: str) -> str:
    """去掉键结尾的括号注解，如“国家代码（例：CN）” -> “国家代码”。"""
    return re.sub(r"[（(][^（）()]*[）)]\s*$", "", key).strip()


def find_placeholders(text: str) -> list[str]:
    """返回文本中出现的所有占位符键（去重，保持出现顺序）。"""
    if not text:
        return []
    seen: list[str] = []
    for m in _PLACEHOLDER_RE.finditer(text):
        key = next(g for g in m.groups() if g is not None).strip()
        if key not in seen:
            seen.append(key)
    return seen


def has_placeholder(text: str) -> bool:
    return bool(text) and _PLACEHOLDER_RE.search(text) is not None


def render_text(text: str, values: dict | None = None) -> RenderResult:
    """把文本中的占位符替换为 values 中的值；缺失的键保持原样并记入 unresolved。"""
    values = values or {}
    unresolved: list[str] = []
    replacements = 0

    def _lookup(key: str):
        if key in values:
            return values[key]
        normalized = _normalize_key(key)
        if normalized and normalized in values:
            return values[normalized]
        return None

    def _repl(m: re.Match) -> str:
        nonlocal replacements
        key = next(g for g in m.groups() if g is not None).strip()
        value = _lookup(key)
        if value is not None:
            replacements += 1
            return str(value)
        if key not in unresolved:
            unresolved.append(key)
        return m.group(0)

    rendered = _PLACEHOLDER_RE.sub(_repl, text)
    return RenderResult(rendered=rendered, unresolved=unresolved, replacements=replacements)


def single_placeholder(text: str) -> str | None:
    """若文本整体恰好是一个占位符，返回其键；否则返回 None。"""
    if not text:
        return None
    m = _PLACEHOLDER_RE.fullmatch(text.strip())
    if not m:
        return None
    return next(g for g in m.groups() if g is not None).strip()