import matplotlib.pyplot as plt
from functions import *


def generate_picture_wp(all_group_vars, picture_path, DEBUG=False):
    vars = all_group_vars['wp']
    WPR_X, WPR_Y, WPR_Z, WPF_X, WPF_Y, WPF_Z, WP_CLP_OFFSET_X, WP_GRP_OFFSET_Z = (float(vars[k]) for k in
                                                                                  ['WPR_X', 'WPR_Y', 'WPR_Z', 'WPF_X',
                                                                                   'WPF_Y', 'WPF_Z', 'WP_CLP_OFFSET_X',
                                                                                   'WP_GRP_OFFSET_Z'])

    if min(WPR_X, WPR_Y, WPR_Z) < 0:
        raise ValueError("Dimensions must be positive.")

    fig, ax = plt.subplots(subplot_kw={'projection': '3d'})

    # Define raw workpiece dimensions
    x_cube, y_cube, z_cube = WPR_X,WPR_Y, WPR_Z
    vertices_raw = np.array([[0, 0, 0], [x_cube, 0, 0], [x_cube, y_cube, 0], [0, y_cube, 0],
                             [0, 0, WPR_Z], [x_cube, 0, WPR_Z], [x_cube, y_cube, WPR_Z], [0, y_cube, WPR_Z]])
    faces_raw = [vertices_raw[[0, 1, 2, 3]], vertices_raw[[4, 5, 6, 7]], vertices_raw[[0, 3, 7, 4]],
                 vertices_raw[[1, 2, 6, 5]], vertices_raw[[0, 1, 5, 4]], vertices_raw[[2, 3, 7, 6]]]

    # Set axis properties
    ax.set_box_aspect([x_cube, y_cube, z_cube])
    ax.set(xticks=[], yticks=[], zticks=[])

    # Draw WP coordinate system
    axis_len = max(x_cube, y_cube, z_cube) * 0.2
    colors = ['r', 'g', 'b']
    origin_x = 0
    origin_y = 0
    origin_z = 0
    for i, vec in enumerate(np.eye(3)):
        ax.quiver(origin_x, origin_y, origin_z, *(axis_len * vec), color=colors[i], linewidth=3)
    ax.text(origin_x, origin_y, origin_z - axis_len * 0.3, 'WP', color='black', fontsize=9, weight='bold', ha='center',
            va='top')

    # Draw WP
    ax.add_collection3d(Poly3DCollection(faces_raw, facecolors='k', linewidths=1, edgecolors='k', alpha=.15))

    # Draw gripping point
    u, v = np.mgrid[0:2 * np.pi:20j, 0:np.pi:20j]
    ball_radius = min(WPR_X, WPR_Y, WPR_Z) * 0.05
    ax.plot_surface(
        WPR_X/2 + ball_radius * np.cos(u) * np.sin(v),
        WPR_Y/2 + ball_radius * np.sin(u) * np.sin(v),
        WPR_Z + ball_radius * np.cos(v),
        color='r'
    )

    # Draw gripper
    gripper_thickness = max(x_cube, y_cube, z_cube) * 0.1
    gripper_wide = WPR_X * 0.4
    GRP_ALPHA = .40
    bars = [
        ((x_cube - gripper_wide) * 0.5, -gripper_thickness, WPR_Z - WP_GRP_OFFSET_Z),
        ((x_cube - gripper_wide) * 0.5, y_cube, WPR_Z - WP_GRP_OFFSET_Z),
    ]
    for (x, y, z) in bars:
        ax.bar3d(
            x, y, z,
            gripper_wide, gripper_thickness, 5 * WPR_Z + WP_GRP_OFFSET_Z,
            color='r', alpha=GRP_ALPHA, edgecolor='k', linewidth=0.5
        )

    # Define finished workpiece dimensions
    x_cube2, y_cube2, z_cube2 = WPR_X + WPF_X,WPR_Y + WPF_Y,WPR_Z + WPF_Z

    # Draw gripping point for finished workpiece
    u, v = np.mgrid[0:2 * np.pi:20j, 0:np.pi:20j]
    ball_radius = min(WPR_X, WPR_Y, WPR_Z) * 0.05
    ax.plot_surface(
        WPR_X/2+WPF_X + ball_radius * np.cos(u) * np.sin(v),
        WPR_Y/2+WPF_Y + ball_radius * np.sin(u) * np.sin(v),
        WPR_Z+WPF_Z + ball_radius * np.cos(v),
        color='g'
    )

    # Draw gripper for finished workpiece
    gripper_thickness2 = max(x_cube, y_cube, z_cube) * 0.05
    gripper_wide2 = WPR_X * 0.4
    GRP_ALPHA2 = .25
    yyy2 = [-gripper_thickness2, y_cube2] if WPF_Y < WPR_Y else [-gripper_thickness2 + (WPF_Y - WPR_Y) * 2, y_cube]
    bars = [
        ((x_cube2 - gripper_wide2) * 0.5, yyy2[0],WPR_Z + WPF_Z - WP_GRP_OFFSET_Z),
        ((x_cube2 - gripper_wide2) * 0.5, yyy2[1], WPR_Z +WPF_Z - WP_GRP_OFFSET_Z),
    ]
    for (x, y, z) in bars:
        ax.bar3d(
            x, y, z,
            gripper_wide2, gripper_thickness2, 5 *WPR_Z +WPF_Z + WP_GRP_OFFSET_Z,
            color='g', alpha=GRP_ALPHA2, edgecolor='k', linewidth=0.5
        )

    # Draw CLP coordinate system
    axis_len = max(x_cube, y_cube, z_cube) * 0.15
    colors = ['r', 'g', 'b']
    origin_x = WPR_X/2 - WP_CLP_OFFSET_X
    origin_y = WPR_Y/2
    origin_z = 0
    for i, vec in enumerate(np.eye(3)):
        ax.quiver(origin_x, origin_y, origin_z, *(axis_len * vec), color=colors[i], linewidth=3)
    ax.text(origin_x, origin_y, origin_z - axis_len * 0.3, 'CLP', color='blue', fontsize=9, weight='bold', ha='center',
            va='top')



    try:
        CLP_BACKENWEITE, CLP_BACKENHOHE, CLP_SPANNHOHE, CLP_AUFLAGETIEFE,MESSPOS_Z = (
            float(all_group_vars['clp'][k]) for k in
        ['CLP_BACKENWEITE', 'CLP_BACKENHOHE', 'CLP_SPANNHOHE', 'CLP_AUFLAGETIEFE','MESSPOS_Z']
        )
    except (KeyError, ValueError):
        CLP_BACKENWEITE = 100
        CLP_BACKENHOHE = 50
        CLP_SPANNHOHE = 5
        CLP_AUFLAGETIEFE = 5
        MESSPOS_Z = 5

    # Define clamping block dimensions
    clp_deep = MESSPOS_Z
    base_x = WPR_X/2 - CLP_BACKENWEITE / 2
    alpha = 0.35
    color = 'blue'
    linewidth = 1

    # Draw clamping blocks
    x = base_x
    dx = CLP_BACKENWEITE
    y = 0
    dy1 = clp_deep
    dy2 = CLP_AUFLAGETIEFE
    z = 0
    dz1 = CLP_SPANNHOHE
    dz2 = CLP_BACKENHOHE
    plot_clamping(ax, x, y, z, dx, dy1, dy2, dz1, dz2, color=color,
                  alpha=alpha, linewidth=linewidth)
    y = y_cube
    plot_clamping(ax, x, y, z, dx, dy1, dy2, dz1, dz2, color=color,
                  alpha=alpha, linewidth=linewidth, inverty=True)

    # Set view properties
    z_trans = WPR_Z*0.2
    zoom_factor = 1.1  # Adjust this factor to zoom out more or less
    ax.view_init(elev=30, azim=-160)
    ax.set_xlim([-x_cube * zoom_factor * 0.1, x_cube * zoom_factor])
    ax.set_ylim([-y_cube * zoom_factor * 0.1, y_cube * zoom_factor])
    ax.set_zlim([-WPR_Z * zoom_factor * 0.1 - z_trans, WPR_Z * zoom_factor - z_trans])
    ax.set_aspect('auto')
    ax.grid(False)  # Remove grid lines
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_zticks([])
    for axis in [ax.xaxis, ax.yaxis, ax.zaxis]:
        axis.set_pane_color((1, 1, 1, 0))  # Hide background panes
        axis.line.set_color((1, 1, 1, 0))  # Hide axis lines

    # Save or display the plot
    if not DEBUG:
        fig.savefig(picture_path, bbox_inches='tight', dpi=300, transparent=True)
    else:
        plt.show()
    plt.close()


if __name__ == "__main__":
    vars = {'WPR_X': 20,
            'WPR_Y': 15,
            'WPR_Z': 20,
            'WPF_X': 10,
            'WPF_Y': 18,
            'WPF_Z': 15,
            'WP_CLP_OFFSET_X': 3,
            'WP_GRP_OFFSET_Z': 5}
    generate_picture_wp({'wp': vars}, "cfg_picture/TEST_wpraw.jpg", DEBUG=True)
