def test_template_crud_packs_and_unpacks_mapping_rules(client):
    payload = {
        "name": "Template",
        "color": "#06b6d4",
        "z_index": 0,
        "classes": [{"id": "c1", "name": "胆囊", "color": "#ff0000", "zIndex": 10}],
        "rules": [{"id": "r1", "name": "rule"}],
    }

    created = client.post("/api/templates", json=payload)
    assert created.status_code == 201
    template_id = created.json()["id"]
    assert created.json()["classes"][0]["name"] == "胆囊"
    assert created.json()["rules"][0]["id"] == "r1"

    listing = client.get("/api/templates")
    assert listing.status_code == 200
    assert listing.json()[0]["classes"][0]["name"] == "胆囊"

    detail = client.get(f"/api/templates/{template_id}")
    assert detail.status_code == 200
    assert detail.json()["name"] == "Template"

    updated = client.patch(f"/api/templates/{template_id}", json={
        "classes": [{"id": "c2", "name": "肝脏", "color": "#00ff00", "zIndex": 20}],
        "rules": [],
    })
    assert updated.status_code == 200
    assert updated.json()["classes"][0]["name"] == "肝脏"

    deleted = client.delete(f"/api/templates/{template_id}")
    assert deleted.status_code == 204
    assert client.get(f"/api/templates/{template_id}").status_code == 404


def test_template_404s(client):
    assert client.get("/api/templates/999").status_code == 404
    assert client.patch("/api/templates/999", json={"name": "x"}).status_code == 404
    assert client.delete("/api/templates/999").status_code == 404


def test_default_head_neck_ct_template_is_seeded_and_visible(client, db_session):
    from main import ensure_default_templates
    from models import Template

    ensure_default_templates(db_session)
    ensure_default_templates(db_session)

    templates = db_session.query(Template).filter(Template.owner_user_id.is_(None)).all()
    names = [template.name for template in templates]
    assert names.count("头颈部CT分割") == 1

    listing = client.get("/api/templates")
    assert listing.status_code == 200
    head_neck = next(template for template in listing.json() if template["name"] == "头颈部CT分割")
    assert head_neck["description"] == "头颈部CT分割"
    expected_names = [
        "肿瘤/结节",
        "下颌骨",
        "甲状腺",
        "气管",
        "颈椎",
        "颈动脉",
        "颈静脉",
        "腮腺",
        "下颌下腺",
        "舌骨",
        "待分类",
    ]
    expected_colors = [
        "#ff0000",
        "#00ff00",
        "#0000ff",
        "#ffff00",
        "#ff00ff",
        "#00ffff",
        "#ff8000",
        "#800080",
        "#008080",
        "#808000",
        "#000000",
    ]
    actual_names = [item["name"] for item in head_neck["classes"]]
    actual_colors = [item["color"] for item in head_neck["classes"]]
    actual_mask_ids = [item["maskId"] for item in head_neck["classes"]]
    if actual_names != expected_names:
        raise AssertionError(f"Unexpected head-neck classes: {actual_names}")
    if actual_colors != expected_colors:
        raise AssertionError(f"Unexpected head-neck colors: {actual_colors}")
    if actual_mask_ids != [*list(range(1, 11)), 0]:
        raise AssertionError(f"Unexpected head-neck mask IDs: {actual_mask_ids}")


def test_default_head_neck_ct_template_migrates_legacy_english_labels(db_session):
    from main import ensure_default_templates
    from models import Template

    db_session.add(Template(
        name="头颈部CT分割",
        description="legacy",
        color="#ef4444",
        z_index=10,
        owner_user_id=None,
        mapping_rules={
            "classes": [
                {"id": "old-1", "name": "肿瘤/结节 (Tumor/Nodule)", "color": "#ff0000", "zIndex": 10, "maskId": 1},
                {"id": "reserved-unclassified", "name": "待分类", "color": "#000000", "zIndex": 0, "maskId": 0},
            ],
            "rules": [],
        },
    ))
    db_session.commit()

    ensure_default_templates(db_session)

    templates = db_session.query(Template).filter(Template.name == "头颈部CT分割").all()
    assert len(templates) == 1
    classes = templates[0].mapping_rules["classes"]
    assert classes[0]["name"] == "肿瘤/结节"
    assert all("(" not in item["name"] for item in classes)
