#!/usr/bin/env python3
"""Verify v2 layout — should have zero crossings and >= 40px gaps."""

nodes = {
    "user":      (30, 430, 100, 50),
    "cli":       (170, 400, 135, 110),
    "kernel":    (340, 90, 190, 380),
    "sqlite":    (570, 90, 130, 55),
    "ws":        (570, 260, 130, 210),
    "compiler":  (770, 90, 250, 580),
    "types":     (430, 770, 420, 60),
    "claude":    (1080, 420, 110, 55),
}

arrows = [
    ("user->cli",        "user", "cli", 130, 455, 168, 455),
    ("cli->kernel",      "cli", "kernel", 305, 425, 338, 425),
    ("cli->compiler",    "cli", "compiler", 305, 485, 768, 485),
    ("compiler->kernel", "compiler", "kernel", 770, 150, 534, 150),
    ("kernel->sqlite",   "kernel", "sqlite", 532, 120, 568, 120),
    ("kernel->ws",       "kernel", "ws", 532, 350, 568, 350),
    ("compiler->ws",     "compiler", "ws", 770, 350, 702, 350),
    ("compiler->claude", "compiler", "claude", 1020, 447, 1078, 447),
]

def seg_rect(x1, y1, x2, y2, rx, ry, rw, rh):
    xmin, ymin, xmax, ymax = rx, ry, rx+rw, ry+rh
    dx, dy = x2-x1, y2-y1
    p = [-dx, dx, -dy, dy]
    q = [x1-xmin, xmax-x1, y1-ymin, ymax-y1]
    te, tx = 0.0, 1.0
    for i in range(4):
        if p[i] == 0:
            if q[i] < 0: return False
        else:
            t = q[i]/p[i]
            if p[i] < 0: te = max(te, t)
            else: tx = min(tx, t)
    # shrink by tiny epsilon so pure-edge touch doesn't count as crossing
    return te < tx

def in_rect(px, py, r, pad=1):
    x,y,w,h = r
    return x+pad < px < x+w-pad and y+pad < py < y+h-pad

def on_edge(px, py, r, tol=4):
    x,y,w,h = r
    left   = abs(px-x) <= tol and y-tol <= py <= y+h+tol
    right  = abs(px-(x+w)) <= tol and y-tol <= py <= y+h+tol
    top    = abs(py-y) <= tol and x-tol <= px <= x+w+tol
    bottom = abs(py-(y+h)) <= tol and x-tol <= px <= x+w+tol
    return left or right or top or bottom

print("="*72)
print("  ARROW CROSSES A NON-ENDPOINT COMPONENT")
print("="*72)
bad = 0
for aid, s, d, x1,y1,x2,y2 in arrows:
    for n, r in nodes.items():
        if n in (s, d): continue
        if seg_rect(x1,y1,x2,y2, *r):
            print(f"  BAD  {aid:<22}  passes through  {n}")
            bad += 1
print(f"  clean ({len(arrows)} arrows, 0 crossings)" if bad==0 else f"  ({bad} collisions)")

print()
print("="*72)
print("  ENDPOINT PLACEMENT")
print("="*72)
issues = 0
for aid, s, d, x1,y1,x2,y2 in arrows:
    sr, dr = nodes[s], nodes[d]
    msgs = []
    if in_rect(x1,y1,sr) and not on_edge(x1,y1,sr):
        msgs.append(f"origin inside {s}"); issues+=1
    if not in_rect(x1,y1,sr) and not on_edge(x1,y1,sr):
        msgs.append(f"origin detached from {s}"); issues+=1
    if in_rect(x2,y2,dr) and not on_edge(x2,y2,dr):
        msgs.append(f"tip inside {d}"); issues+=1
    if not in_rect(x2,y2,dr) and not on_edge(x2,y2,dr):
        msgs.append(f"tip detached from {d}"); issues+=1
    if msgs:
        print(f"  FIX  {aid:<22}  {'; '.join(msgs)}")
if issues==0:
    print("  clean — every arrow attaches cleanly to both endpoint edges")

print()
print("="*72)
print("  SPACING (node-node gaps, rule: >= 40px where axes overlap)")
print("="*72)
def gap_h(a, b):
    ax,ay,aw,ah = a; bx,by,bw,bh = b
    if ay+ah < by or by+bh < ay: return None
    if ax+aw <= bx: return bx - (ax+aw)
    if bx+bw <= ax: return ax - (bx+bw)
    return -1
def gap_v(a, b):
    ax,ay,aw,ah = a; bx,by,bw,bh = b
    if ax+aw < bx or bx+bw < ax: return None
    if ay+ah <= by: return by - (ay+ah)
    if by+bh <= ay: return ay - (by+bh)
    return -1
tight = 0
keys = list(nodes)
for i,a in enumerate(keys):
    for b in keys[i+1:]:
        g = gap_h(nodes[a], nodes[b])
        if g is not None and 0 <= g < 40:
            print(f"  TIGHT-H  {a} <-> {b}  gap={g}px"); tight+=1
        g = gap_v(nodes[a], nodes[b])
        if g is not None and 0 <= g < 40:
            print(f"  TIGHT-V  {a} <-> {b}  gap={g}px"); tight+=1
if tight==0:
    print("  clean — all gaps >= 40px")

print()
print("="*72)
print("  CANVAS (viewBox 1240 x 920)")
print("="*72)
mx = max(n[0]+n[2] for n in nodes.values())
my = max(n[1]+n[3] for n in nodes.values())
print(f"  rightmost node x: {mx}   (margin: {1240-mx})")
print(f"  bottom node y:    {my}   (margin: {920-my} — legend occupies 870-906)")
