#!/usr/bin/env python3
"""E2E: 边 CRUD + 标签解析"""
from helper import *

header("Edges")

pid = create_project(unique_name("E2E-边"))
n1 = create_node(pid, "源", "host")["id"]
n2 = create_node(pid, "目标", "service", after=n1, edge_label="发现目标")["id"]

# ── Create ──
eid = assert_ok(post(f"/api/v1/projects/{pid}/edges", {
    "source_node_id": n1, "target_node_id": n2, "label": "SSH连接"
}))["id"]
ok("create edge")

# ── List ──
edges = assert_ok(get(f"/api/v1/projects/{pid}/edges"))
assert len(edges) == 2
ok("list edges")

# ── Resolve nodes by label ──
assert_ok(post(f"/api/v1/projects/{pid}/edges", {
    "source_label": "源", "target_label": "目标", "label": "标签解析边"
}))
edges = assert_ok(get(f"/api/v1/projects/{pid}/edges"))
assert any(e["label"] == "标签解析边" for e in edges)
ok("resolve edge endpoints by label")

# Missing labels are rejected instead of auto-created
assert_err(post(f"/api/v1/projects/{pid}/edges", {
    "source_label": "自动源", "target_label": "自动目标", "label": "自动边"
}), 400)
ok("reject edge labels that do not match nodes")

# Duplicate edges are rejected
assert_err(post(f"/api/v1/projects/{pid}/edges", {
    "source_node_id": n1, "target_node_id": n2, "label": "SSH连接"
}), 409)
ok("reject duplicate edge")

# Self-loop edges are rejected
assert_err(post(f"/api/v1/projects/{pid}/edges", {
    "source_node_id": n1, "target_node_id": n1, "label": "自环"
}), 400)
ok("reject self-loop edge")

# ── Update ──
assert_ok(put(f"/api/v1/projects/{pid}/edges/{eid}", {"label": "SSH隧道"}))
e = assert_ok(get(f"/api/v1/projects/{pid}/edges"))
assert any(ed["label"] == "SSH隧道" for ed in e)
ok("update edge label")

# ── Delete ──
assert_ok(delete(f"/api/v1/projects/{pid}/edges/{eid}"))
ok("delete edge")

# 404
assert_err(put(f"/api/v1/projects/{pid}/edges/{eid}", {"label": "x"}), 404)
ok("404 on deleted edge update")

delete_project(pid)

summary()
