import json
import math

# 字段集合来自本系列共用的工单契约；多字段和少字段都拒绝。
FIELDS = {"category", "urgency", "order_id", "requested_amount", "summary"}


def unique_object(pairs):
    """拒绝重复 JSON 属性，避免前后两个 category 被不同组件解释为不同值。"""
    result = {}
    for key, value in pairs:
        if key in result:
            raise ValueError("JSON 含重复字段")
        result[key] = value
    return result


def reject_constant(value):
    """Python 默认容忍某些非标准常量；本契约拒绝它们。"""
    raise ValueError("JSON 不允许 NaN 或 Infinity")


def validate(raw):
    """把原始 JSON 文本解析成已通过类型检查的工单；失败时抛出异常。"""
    item = json.loads(raw, object_pairs_hook=unique_object, parse_constant=reject_constant)
    if not isinstance(item, dict) or set(item) != FIELDS:
        raise ValueError("字段缺失或包含未定义字段")
    if item["category"] not in ("billing", "security", "general", "unknown"):
        raise ValueError("category 不属于约定枚举")
    if item["urgency"] not in ("low", "medium", "high"):
        raise ValueError("urgency 不属于约定枚举")
    order_id = item["order_id"]
    if order_id is not None and (not isinstance(order_id, str) or not order_id.strip()):
        raise ValueError("order_id 必须为非空字符串或 null")
    amount = item["requested_amount"]
    # Python 中 bool 是 int 的子类；这里用精确类型检查，防止把 true 当金额 1。
    # 拒绝 NaN 和无穷大，因为它们不是合法的业务金额。
    if amount is not None and (
        type(amount) not in (int, float) or not math.isfinite(amount) or amount < 0
    ):
        raise ValueError("requested_amount 必须为非负有限数字或 null")
    if not isinstance(item["summary"], str) or not 1 <= len(item["summary"]) <= 40:
        raise ValueError("summary 长度必须在 1 到 40 个字符之间")
    return item


def check_order(item, orders, actor):
    """核验订单事实和归属；actor 必须来自登录态，不能从模型输出取得。"""
    if item["order_id"] is None:
        return "需要补充订单号"
    order = orders.get(item["order_id"])
    # 不向调用者区分不存在与无权访问，避免泄露其他用户的订单信息。
    if order is None or order["owner"] != actor:
        return "订单不可用"
    return "订单已找到，退款资格仍需另行核验"


if __name__ == "__main__":
    # 教学响应：故意给出一个不存在的订单，观察两层校验的不同结果。
    raw = json.dumps({
        "category": "billing", "urgency": "medium", "order_id": "A999",
        "requested_amount": 99, "summary": "申请退款",
    }, ensure_ascii=False)
    ticket = validate(raw)
    print("格式校验通过")
    print(check_order(ticket, {"A100": {"owner": "user-1"}}, "user-1"))
