"""
범례 심볼 프로브 — 좌표 박스 내 프리미티브 추출 + 정규화 시그니처 도출.

사용:
  python3 mcp-server/legend_probe.py XMIN YMIN XMAX YMAX [라벨]

출력:
  1) 원시 프리미티브 (LINE/ARC/CIRCLE/LWPOLYLINE)
  2) 정규화 시그니처: 앵커=박스 좌하단 기준 상대좌표,
     도형종류별 개수, 선분 길이·각도, 공유 정점(연결 토폴로지),
     폐합 삼각형 등 패턴 단서
"""
import sys, math, collections
import ezdxf
from ezdxf import recover

DXF = "dxf-graph/No-10_Plant_PID.dxf"


def load():
    try:
        return ezdxf.readfile(DXF)
    except ezdxf.DXFStructureError:
        d, _ = recover.readfile(DXF)
        return d


def main():
    if len(sys.argv) < 5:
        print("usage: legend_probe.py XMIN YMIN XMAX YMAX [label]")
        sys.exit(1)
    x0, y0, x1, y1 = map(float, sys.argv[1:5])
    label = sys.argv[5] if len(sys.argv) > 5 else "?"
    if x0 > x1:
        x0, x1 = x1, x0
    if y0 > y1:
        y0, y1 = y1, y0

    msp = load().modelspace()

    def inb(x, y):
        return x0 <= x <= x1 and y0 <= y <= y1

    lines, arcs, circles, polys, texts = [], [], [], [], []
    for e in msp:
        t = e.dxftype()
        try:
            if t == "LINE":
                s, en = e.dxf.start, e.dxf.end
                if inb(s.x, s.y) or inb(en.x, en.y):
                    lines.append(((s.x, s.y), (en.x, en.y)))
            elif t == "ARC":
                c = e.dxf.center
                if inb(c.x, c.y):
                    arcs.append((c.x, c.y, e.dxf.radius,
                                 e.dxf.start_angle, e.dxf.end_angle))
            elif t == "CIRCLE":
                c = e.dxf.center
                if inb(c.x, c.y):
                    circles.append((c.x, c.y, e.dxf.radius))
            elif t == "LWPOLYLINE":
                p = [(a, b) for a, b in e.get_points("xy")]
                if p and inb(p[0][0], p[0][1]):
                    polys.append(p)
            elif t in ("TEXT", "MTEXT"):
                ip = e.dxf.insert
                if inb(ip.x, ip.y):
                    v = (e.plain_text() if t == "MTEXT" else e.dxf.text).strip()
                    if v:
                        texts.append((round(ip.x, 1), round(ip.y, 1), v[:40]))
        except Exception:
            pass

    print(f"=== '{label}'  box=({x0:.1f},{y0:.1f})-({x1:.1f},{y1:.1f}) ===")
    print(f"LINE={len(lines)} ARC={len(arcs)} CIRCLE={len(circles)} "
          f"LWPOLY={len(polys)} TEXT={len(texts)}")
    if texts:
        print("텍스트:", [t[2] for t in texts])

    # 앵커 = 비텍스트 프리미티브 최소 x,y
    pts = []
    for a, b in lines:
        pts += [a, b]
    for cx, cy, r, *_ in arcs:
        pts += [(cx - r, cy - r), (cx + r, cy + r)]
    for cx, cy, r in circles:
        pts += [(cx - r, cy - r), (cx + r, cy + r)]
    for p in polys:
        pts += p
    if not pts:
        print("(비텍스트 프리미티브 없음)")
        return
    ax = min(p[0] for p in pts)
    ay = min(p[1] for p in pts)
    w = max(p[0] for p in pts) - ax
    h = max(p[1] for p in pts) - ay
    print(f"앵커=({ax:.2f},{ay:.2f})  정규화 bbox= {w:.2f} x {h:.2f}")

    def n(x, y):
        return (round(x - ax, 2), round(y - ay, 2))

    print("\n-- LINE (상대좌표 | 길이 | 각도°) --")
    seg = []
    for (sx, sy), (ex, ey) in sorted(lines):
        ln = math.hypot(ex - sx, ey - sy)
        ang = round(math.degrees(math.atan2(ey - sy, ex - sx)) % 180, 1)
        print(f"  {n(sx,sy)} → {n(ex,ey)}  len={ln:.2f}  ang={ang}")
        seg.append((n(sx, sy), n(ex, ey), round(ln, 2), ang))
    for cx, cy, r in circles:
        print(f"-- CIRCLE c={n(cx,cy)} r={r:.2f}")
    for cx, cy, r, sa, ea in arcs:
        print(f"-- ARC c={n(cx,cy)} r={r:.2f} {sa:.0f}°→{ea:.0f}°")
    for p in polys:
        print(f"-- LWPOLY {[n(x,y) for x,y in p]}")

    # 공유 정점 (연결 토폴로지) — 0.3u 이내 동일점
    vtx = collections.defaultdict(int)
    for s, e, *_ in seg:
        vtx[s] += 1
        vtx[e] += 1
    shared = {v: c for v, c in vtx.items() if c >= 3}
    print(f"\n공유정점(차수≥3 = apex/junction): {shared}")
    ang_hist = collections.Counter(s[3] for s in seg)
    print(f"각도 분포: {dict(ang_hist)}")
    print(f"선분 길이 분포: {sorted(s[2] for s in seg)}")


if __name__ == "__main__":
    main()
