#!/usr/bin/env python3
"""Compute which arrows cross through non-endpoint component boxes."""

nodes = {
    "user":      (30, 375, 90, 50),
    "cli":       (150, 360, 130, 90),
    "kernel":    (340, 90, 200, 360),
    "sqlite":    (590, 145, 120, 55),
    "ws":        (590, 220, 120, 220),
    "compiler":  (780, 90, 240, 560),
    "types":     (430, 700, 400, 60),
    "claude":    (1080, 375, 100, 50),
}

arrows = [
    ("user->cli",        "user", "cli", 120, 400, 148, 400),
    ("cli->kernel",      "cli", "kernel", 280, 385, 338, 220),
    ("cli->compiler",    "cli", "compiler", 280, 415, 778, 220),
    ("compiler->kernel", "compiler", "kernel", 778, 500, 542, 380),
    ("kernel->sqlite",   "kernel", "sqlite", 542, 170, 588, 170),
    ("kernel->ws",       "kernel", "ws", 542, 240, 588, 290),
    ("compiler->claude", "compiler", "claude", 1022, 400, 1078, 400),
]

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)
    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"  ({bad} collisions)" if bad else "  clean")

print()
print("="*72)
print("  ENDPOINT PLACEMENT")
print("="*72)
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}")
    if not in_rect(x1,y1,sr) and not on_edge(x1,y1,sr):
        msgs.append(f"origin detached from {s}")
    if in_rect(x2,y2,dr) and not on_edge(x2,y2,dr):
        msgs.append(f"tip inside {d}")
    if not in_rect(x2,y2,dr) and not on_edge(x2,y2,dr):
        msgs.append(f"tip detached from {d}")
    if msgs:
        print(f"  FIX  {aid:<22}  {'; '.join(msgs)}")

print()
print("="*72)
print("  BOX-BOX OVERLAPS")
print("="*72)
overlaps = 0
keys = list(nodes)
for i,a in enumerate(keys):
    for b in keys[i+1:]:
        (ax,ay,aw,ah) = nodes[a]
        (bx,by,bw,bh) = nodes[b]
        if ax < bx+bw and ax+aw > bx and ay < by+bh and ay+ah > by:
            print(f"  OVERLAP  {a} ∩ {b}")
            overlaps += 1
print(f"  ({overlaps})" if overlaps else "  clean")

print()
print("="*72)
print("  VIEWBOX (declared: 1200 x 820)")
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 to viewBox right: {1200-mx})")
print(f"  bottom node y:    {my}   (margin to viewBox bottom: {820-my})")

print()
print("="*72)
print("  SPACING (min horizontal/vertical gaps — rule says >= 40px)")
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  # no vertical overlap
    if ax+aw <= bx: return bx - (ax+aw)
    if bx+bw <= ax: return ax - (bx+bw)
    return -1  # overlapping
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
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 (want >= 40)")
        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 (want >= 40)")
