import numpy as np
import open3d as o3d


def get_ground_truth_seams():
    """返回你手动测量的三维坐标（物体坐标系）。"""
    ground_truth = {
        'up_line1': {
            'start_3d': np.array([142.2, 0, 7.3]),
            'end_3d': np.array([153.9, 0, 149.8])
        },
        'up_line2': {
            'start_3d': np.array([142.2, 0, 7.3]),
            'end_3d': np.array([142.2, 50.3, 7.3])
        },
        'bottom_line1': {
            'start_3d': np.array([8.9, 0, 7.3]),
            'end_3d': np.array([140.2, 0, 7.3])
        },
        'bottom_line2': {
            'start_3d': np.array([142.2, 0, 7.3]),
            'end_3d': np.array([142.2, 50.3, 7.3])
        }
    }
    return ground_truth


def align_and_stitch_seams(reconstructed_seams):
    """
    使用ICP算法将重建的点云对齐到地面真实坐标系，并进行拼接。

    Args:
        reconstructed_seams (dict): 在相机坐标系下重建出的焊缝端点。

    Returns:
        dict: 在物体坐标系下对齐和拼接后的焊缝端点。
    """
    print("\n--- Aligning and Stitching Seams to Ground Truth ---")

    ground_truth = get_ground_truth_seams()

    # --- 1. 对齐上半部分 (up) ---
    # 源点云：重建出的 up_line2 (相机坐标系)
    source_points_up = np.array([
        reconstructed_seams['up_line2']['start_3d'],
        reconstructed_seams['up_line2']['end_3d']
    ])
    source_pcd_up = o3d.geometry.PointCloud()
    source_pcd_up.points = o3d.utility.Vector3dVector(source_points_up)

    # 目标点云：测量的 up_line2 (物体坐标系)
    target_points_up = np.array([
        ground_truth['up_line2']['start_3d'],
        ground_truth['up_line2']['end_3d']
    ])
    target_pcd_up = o3d.geometry.PointCloud()
    target_pcd_up.points = o3d.utility.Vector3dVector(target_points_up)

    print("Aligning 'up' part...")
    # 使用点对点ICP计算变换矩阵 M_up
    # 由于只有两个点，我们可以直接计算一个精确的变换，但用ICP更通用
    # estimate_rigid_transformation 需要点是 (3, N) 的格式
    trans_up = o3d.pipelines.registration.TransformationEstimationPointToPoint().compute_transformation(
        source_pcd_up, target_pcd_up, o3d.utility.Vector2iVector([[0, 0], [1, 1]]))

    print("Transformation matrix for 'up' part (Camera -> Object):")
    print(trans_up)

    # --- 2. 对齐下半部分 (bottom) ---
    # 源点云：重建出的 bottom_line2 (相机坐标系)
    source_points_bottom = np.array([
        reconstructed_seams['bottom_line2']['start_3d'],
        reconstructed_seams['bottom_line2']['end_3d']
    ])
    source_pcd_bottom = o3d.geometry.PointCloud()
    source_pcd_bottom.points = o3d.utility.Vector3dVector(source_points_bottom)

    # 目标点云：测量的 bottom_line2 (物体坐标系)
    target_points_bottom = np.array([
        ground_truth['bottom_line2']['start_3d'],
        ground_truth['bottom_line2']['end_3d']
    ])
    target_pcd_bottom = o3d.geometry.PointCloud()
    target_pcd_bottom.points = o3d.utility.Vector3dVector(target_points_bottom)

    print("\nAligning 'bottom' part...")
    trans_bottom = o3d.pipelines.registration.TransformationEstimationPointToPoint().compute_transformation(
        source_pcd_bottom, target_pcd_bottom, o3d.utility.Vector2iVector([[0, 0], [1, 1]]))

    print("Transformation matrix for 'bottom' part (Camera -> Object):")
    print(trans_bottom)

    # --- 3. 应用变换并组合最终结果 ---
    aligned_seams = {}
    for name, points in reconstructed_seams.items():
        # 创建齐次坐标 (x, y, z, 1)
        start_hom = np.append(points['start_3d'], 1)
        end_hom = np.append(points['end_3d'], 1)

        # 根据焊缝属于 'up' 还是 'bottom' 选择对应的变换矩阵
        if 'up' in name:
            transformed_start = (trans_up @ start_hom.T)[:3]
            transformed_end = (trans_up @ end_hom.T)[:3]
        elif 'bottom' in name:
            transformed_start = (trans_bottom @ start_hom.T)[:3]
            transformed_end = (trans_bottom @ end_hom.T)[:3]
        else:
            continue

        aligned_seams[name] = {
            'start_3d': transformed_start,
            'end_3d': transformed_end
        }

    return aligned_seams, ground_truth
