"""配置值变量插值工具。

支持在配置值中使用 ${VAR_NAME} 语法引用内置变量，
在 Webhook pull_configs 下发时统一完成替换。
"""

import re

from pydantic import BaseModel, Field, field_validator

__all__ = [
    "interpolate_config_value",
    "build_context",
    "SUPPORTED_INTERPOLATION_VARS",
    "ContextVariables",
]

_VAR_PATTERN = re.compile(r"\$\{([A-Z_][A-Z0-9_]*)\}")


class ContextVariables(BaseModel):
    """插值上下文变量（强类型，SSOT）。

    此类是插值变量的唯一真实来源：

    - ``SUPPORTED_INTERPOLATION_VARS`` 由字段名自动派生，无需手动维护。
    - ``build_context`` 由 ``model_dump()`` 自动构建，无需手动映射。

    新增内置变量时，**只需在此类添加字段**，其余逻辑自动跟随变化。

    Attributes
    ----------
    global_base_url : str
        当前 hezor2 实例的访问 URL 前缀，对应插值变量 ``${GLOBAL_BASE_URL}``。
        默认为空字符串（不做替换）。尾部斜杠由 validator 自动去除。

    Examples
    --------
    >>> ctx = ContextVariables(global_base_url="https://api.hezor.ai/")
    >>> ctx.global_base_url
    'https://api.hezor.ai'
    """

    global_base_url: str = Field(
        default="",
        description="当前 hezor2 实例访问 URL 前缀（对应 ${GLOBAL_BASE_URL}）",
    )

    @field_validator("global_base_url")
    @classmethod
    def _normalize_url(cls, v: str) -> str:
        return v.rstrip("/")


# 由 ContextVariables 字段名自动派生，无需手动维护。
# 新增变量时只需在 ContextVariables 中添加字段，此集合自动更新。
SUPPORTED_INTERPOLATION_VARS: frozenset[str] = frozenset(
    key.upper() for key in ContextVariables.model_fields
)


def interpolate_config_value(value: str, context: dict[str, str]) -> str:
    """对配置值执行变量插值。

    将 ``${VAR_NAME}`` 占位符替换为 context 中对应的值。
    未在 context 中找到的变量名保留原始占位符，不报错。

    Parameters
    ----------
    value : str
        原始配置值，可能包含 ${VAR} 占位符。
    context : dict[str, str]
        内置变量字典，如 ``{'GLOBAL_BASE_URL': 'https://api.hezor.ai'}``。

    Returns
    -------
    str
        插值替换后的配置值。未识别的变量占位符原样保留。

    Examples
    --------
    >>> ctx = {"GLOBAL_BASE_URL": "api.hezor.ai"}
    >>> interpolate_config_value("https://${GLOBAL_BASE_URL}/api/v1", ctx)
    'https://api.hezor.ai/api/v1'

    >>> # 未识别的变量保留原样
    >>> interpolate_config_value("${UNKNOWN_VAR}", {})
    '${UNKNOWN_VAR}'

    >>> # 无占位符的值原样返回
    >>> interpolate_config_value("simple_value", ctx)
    'simple_value'

    Notes
    -----
    仅在 Webhook ``pull_configs`` 下发时调用，数据库中始终存储原始模板字符串。
    """

    def _replace(match: re.Match) -> str:
        var_name = match.group(1)
        # 用 in 检查而非 or：key 存在但值为空字符串时
        # 应当替换为空字符串，而非 fallback 回原始占位符。
        return context[var_name] if var_name in context else match.group(0)

    return _VAR_PATTERN.sub(_replace, value)


def build_context(context_vars: ContextVariables) -> dict[str, str]:
    """将强类型 ContextVariables 转换为插值上下文字典。

    Parameters
    ----------
    context_vars : ContextVariables
        强类型上下文变量对象。

    Returns
    -------
    dict[str, str]
        可直接传入 :func:`interpolate_config_value` 的上下文字典。
        所有键名均在 :data:`SUPPORTED_INTERPOLATION_VARS` 中定义。

    Examples
    --------
    >>> ctx_vars = ContextVariables(global_base_url="https://api.hezor.ai")
    >>> ctx = build_context(ctx_vars)
    >>> ctx["GLOBAL_BASE_URL"]
    'https://api.hezor.ai'

    >>> # 尾部斜杠由 ContextVariables validator 去除，build_context 无需处理
    >>> ctx_vars = ContextVariables(global_base_url="https://api.hezor.ai/")
    >>> ctx = build_context(ctx_vars)
    >>> ctx["GLOBAL_BASE_URL"]
    'https://api.hezor.ai'
    """
    return {key.upper(): value for key, value in context_vars.model_dump().items()}
