"""
STEP 용접선 추출 테스트 (gmsh OCC 방식)
- 합성 T자 두 판 STEP 생성
- 두 솔리드 경계에서 공유/인접 엣지 추출
- XYZ 점 출력 (우리 solveIK 입력 형식 확인용)
"""
import gmsh
import numpy as np
import os

OUT_DIR = os.path.dirname(os.path.abspath(__file__))
STEP_PATH = os.path.join(OUT_DIR, "test_tplate.step")
RESULT_PATH = os.path.join(OUT_DIR, "weld_edge_points.txt")

def build_t_plate_step():
    """T자 두 판 합성 STEP 생성: 수평판(base) + 수직판(web)"""
    gmsh.initialize()
    gmsh.option.setNumber("General.Terminal", 0)
    gmsh.model.add("t_plate")

    # 수평판 (base): 200 x 200 x 10 mm, Z=0..10
    base = gmsh.model.occ.addBox(0, 0, 0, 200, 200, 10)
    # 수직판 (web): 10 x 200 x 100 mm, X=95..105, Z=10..110
    web  = gmsh.model.occ.addBox(95, 0, 10, 10, 200, 100)

    gmsh.model.occ.synchronize()

    # 두 솔리드 볼륨 확인
    vols = gmsh.model.getEntities(3)
    print(f"볼륨 수: {len(vols)} — {vols}")

    # STEP 저장 (두 솔리드를 별개로 유지)
    gmsh.write(STEP_PATH)
    print(f"STEP 저장: {STEP_PATH}")

    gmsh.finalize()

def extract_weld_edge_from_step():
    """
    STEP 로드 후 두 솔리드의 인접 경계 엣지 추출
    전략:
      - 솔리드 A의 면(surface)과 솔리드 B의 면이 같은 Z 평면에서 만나는 엣지
      - 여기서는 Z=10 평면 위에 있는 엣지를 찾아 용접선으로 지정
    """
    gmsh.initialize()
    gmsh.option.setNumber("General.Terminal", 0)
    gmsh.model.add("weld_test")

    gmsh.model.occ.importShapes(STEP_PATH)
    gmsh.model.occ.synchronize()

    vols = gmsh.model.getEntities(3)
    edges = gmsh.model.getEntities(1)  # 모든 curve(엣지)
    print(f"로드 완료 — 볼륨: {len(vols)}, 엣지: {len(edges)}")

    # 각 엣지의 bounding box 확인 → Z_min == Z_max == 10 인 엣지 = 용접 경계
    weld_edges = []
    for dim, tag in edges:
        xmin, ymin, zmin, xmax, ymax, zmax = gmsh.model.getBoundingBox(dim, tag)
        # Z=10 평면 위에 있고 Y 방향으로 뻗어있는 엣지 (base-web 접합선)
        if abs(zmin - 10.0) < 0.5 and abs(zmax - 10.0) < 0.5:
            # X 범위가 web 폭 내 (95~105)인지 확인
            if 90 < xmin < 110 and 90 < xmax < 110:
                weld_edges.append(tag)
                print(f"  용접 엣지 후보: tag={tag} x=[{xmin:.1f},{xmax:.1f}] y=[{ymin:.1f},{ymax:.1f}] z=[{zmin:.1f},{zmax:.1f}]")

    if not weld_edges:
        print("[경고] Z=10 web 경계 엣지를 못 찾음. 모든 Z=10 엣지를 출력합니다.")
        for dim, tag in edges:
            xmin, ymin, zmin, xmax, ymax, zmax = gmsh.model.getBoundingBox(dim, tag)
            if abs(zmin - 10.0) < 0.5 and abs(zmax - 10.0) < 0.5:
                weld_edges.append(tag)
                print(f"  Z=10 엣지: tag={tag} x=[{xmin:.1f},{xmax:.1f}] y=[{ymin:.1f},{ymax:.1f}]")

    # 엣지를 메쉬화해서 노드 좌표 추출
    for tag in weld_edges:
        gmsh.model.mesh.setTransfiniteCurve(tag, 21)  # 20구간 = 21점
    gmsh.model.mesh.generate(1)

    all_pts = []
    for tag in weld_edges:
        node_tags, coords, _ = gmsh.model.mesh.getNodes(1, tag, includeBoundary=True)
        pts_raw = np.array(coords).reshape(-1, 3)
        all_pts.extend(pts_raw.tolist())

    gmsh.finalize()

    if not all_pts:
        print("[실패] 용접선 점을 추출하지 못했습니다.")
        return

    pts = np.array(all_pts)
    # Y 정렬 (용접 진행방향)
    pts = pts[np.argsort(pts[:, 1])]

    print(f"\n[결과] 용접선 점 {len(pts)}개 추출:")
    print(f"  X 범위: {pts[:,0].min():.1f} ~ {pts[:,0].max():.1f} mm")
    print(f"  Y 범위: {pts[:,1].min():.1f} ~ {pts[:,1].max():.1f} mm")
    print(f"  Z 범위: {pts[:,2].min():.1f} ~ {pts[:,2].max():.1f} mm")
    print(f"  첫 점: X={pts[0,0]:.2f} Y={pts[0,1]:.2f} Z={pts[0,2]:.2f}")
    print(f"  끝 점: X={pts[-1,0]:.2f} Y={pts[-1,1]:.2f} Z={pts[-1,2]:.2f}")

    # 파일 저장
    np.savetxt(RESULT_PATH, pts, fmt="%.3f", header="X Y Z (mm) — STEP 용접선 추출")
    print(f"\n점 데이터 저장: {RESULT_PATH}")

    # solveIK 입력 형식 미리보기 (XYZ만, 방향 갭 인지)
    print("\n[솔직 보고] 우리 solveIK(JS)는 XYZ 위치만 받음 — 토치방향(orientation)은 입력 슬롯 없음.")
    print("  → 현재는 XYZ 점만 추출. 방향은 나중에 별도 갭 해결 필요.")
    print("\nsolveIK 입력 형식 예시:")
    for i, pt in enumerate(pts[::max(1, len(pts)//5)]):
        print(f"  포인트 {i}: {{x: {pt[0]:.1f}, y: {pt[1]:.1f}, z: {pt[2]:.1f}}} mm")

    return pts


if __name__ == "__main__":
    print("=== 1단계: T자 STEP 파일 생성 ===")
    build_t_plate_step()

    print("\n=== 2단계: STEP에서 용접선 엣지 추출 ===")
    pts = extract_weld_edge_from_step()
    print("\n=== 완료 ===")
