from copy import deepcopy
import json
from jsonschema import Draft202012Validator

BASE = {
    "name": "get_customer",
    "description": "IDで顧客を1件取得。名前で探すときはsearch_customers。",
    "inputSchema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
            "customer_id": {"type": "string", "pattern": "^c_[0-9]+$"}
        },
        "required": ["customer_id"],
        "additionalProperties": False,
    },
}
GOLD = {"name": "get_customer", "arguments": {"customer_id": "c_123"}}

def inspect(tools, call):
    # 外形のparseは済んでいるfixture。重複名はcatalogの検査で拒否する。
    names = [t["name"] for t in tools]
    if len(names) != len(set(names)):
        raise ValueError("duplicate tool names")
    for t in tools:
        Draft202012Validator.check_schema(t["inputSchema"])
    selected = next((t for t in tools if t["name"] == call.get("name")), None)
    if selected is None:
        return False, ["unknown_or_missing_tool"]
    if not isinstance(call.get("arguments"), dict):
        return False, ["arguments_must_be_object"]
    errors = list(Draft202012Validator(selected["inputSchema"]).iter_errors(call["arguments"]))
    return not errors, sorted(set(str(e.validator) for e in errors))

cases = []
def add(label, tools, call, expected_valid, gold):
    cases.append((label, tools, call, expected_valid, gold))

add("original", [BASE], GOLD, True, GOLD)

renamed = deepcopy(BASE)
renamed["name"] = "fetch_customer"
new_call = {"name": "fetch_customer", "arguments": {"customer_id": "c_123"}}
add("renamed_tool_old_call", [renamed], GOLD, False, new_call)
add("renamed_tool_new_call", [renamed], new_call, True, new_call)

field = deepcopy(BASE)
field["inputSchema"]["properties"]["client_id"] = field["inputSchema"]["properties"].pop("customer_id")
field["inputSchema"]["required"] = ["client_id"]
field_call = {"name": "get_customer", "arguments": {"client_id": "c_123"}}
add("renamed_field_old_call", [field], GOLD, False, field_call)
add("renamed_field_new_call", [field], field_call, True, field_call)

description = deepcopy(BASE)
description["description"] = "顧客情報を取得する。"
add("description_change_same_call", [description], GOLD, True, GOLD)

optional = deepcopy(BASE)
optional["inputSchema"]["properties"]["include_history"] = {"type": "boolean", "default": False}
add("optional_field_added", [optional], GOLD, True, GOLD)

required = deepcopy(BASE)
required["inputSchema"]["properties"]["region"] = {"type": "string", "enum": ["jp", "sg"]}
required["inputSchema"]["required"].append("region")
required_gold = {"name": "get_customer", "arguments": {"customer_id": "c_123", "region": "jp"}}
add("required_field_added", [required], GOLD, False, required_gold)

typed = deepcopy(BASE)
typed["inputSchema"]["properties"]["customer_id"] = {"type": "integer"}
add("type_changed", [typed], GOLD, False, {"name": "get_customer", "arguments": {"customer_id": 123}})

enum_old = deepcopy(BASE)
enum_old["inputSchema"]["properties"]["status"] = {"type": "string", "enum": ["active", "all"]}
enum_new = deepcopy(enum_old)
enum_new["inputSchema"]["properties"]["status"]["enum"] = ["enabled", "all"]
enum_call = {"name": "get_customer", "arguments": {"customer_id": "c_123", "status": "active"}}
enum_gold = {"name": "get_customer", "arguments": {"customer_id": "c_123", "status": "enabled"}}
add("enum_replaced", [enum_new], enum_call, False, enum_gold)

nested = deepcopy(BASE)
nested["inputSchema"]["properties"] = {"customer": {"type": "object", "properties": {"id": {"type": "string"}}, "required": ["id"], "additionalProperties": False}}
nested["inputSchema"]["required"] = ["customer"]
add("nested_field_missing", [nested], {"name": "get_customer", "arguments": {"customer": {}}}, False,
    {"name": "get_customer", "arguments": {"customer": {"id": "c_123"}}})

summary = deepcopy(BASE)
summary["name"] = "get_customer_summary"
summary["description"] = "IDで顧客の短い要約だけを取得。登録情報全体は返さない。"
add("valid_but_wrong_tool", [BASE, summary], {"name": summary["name"], "arguments": {"customer_id": "c_123"}}, True, GOLD)
add("valid_but_wrong_customer", [BASE], {"name": "get_customer", "arguments": {"customer_id": "c_999"}}, True, GOLD)
add("missing_tool_name", [BASE, summary], {"arguments": {"customer_id": "c_123"}}, False, GOLD)
add("stale_extra_field", [BASE], {"name": "get_customer", "arguments": {"customer_id": "c_123", "client_id": "c_123"}}, False, GOLD)
add("catalog_reordered_same_call", [summary, BASE], GOLD, True, GOLD)

for label, tools, call, expected, gold in cases:
    valid, rules = inspect(tools, call)
    assert valid == expected, (label, valid, rules)
    # この完全一致oracleは架空fixture専用。本番の意味判定器ではない。
    task_correct = valid and call == gold
    print(json.dumps({"case": label, "schema_valid": valid,
                      "task_correct": task_correct, "rules": rules}, ensure_ascii=False))

args = deepcopy(GOLD["arguments"])
Draft202012Validator(optional["inputSchema"]).validate(args)
assert "include_history" not in args  # defaultは挿入されない
print(f"checked={len(cases)}; default_not_inserted=True")
