# SPDX-License-Identifier: GPL-2.0-or-later

# Export wrappers and integration with external tools.


import bpy


def image_get(mat):
    from bpy_extras import node_shader_utils

    if mat.use_nodes:
        mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mat)
        base_color_tex = mat_wrap.base_color_texture
        if base_color_tex and base_color_tex.image:
            return base_color_tex.image


def image_copy_guess(filepath, objects):
    # 'filepath' is the path we are writing to.
    image = None
    mats = set()

    for obj in objects:
        for slot in obj.material_slots:
            if slot.material:
                mats.add(slot.material)

    for mat in mats:
        image = image_get(mat)
        if image is not None:
            break

    if image is not None:
        import os
        import shutil

        imagepath = bpy.path.abspath(image.filepath, library=image.library)
        if os.path.exists(imagepath):
            filepath_noext = os.path.splitext(filepath)[0]
            ext = os.path.splitext(imagepath)[1]

            imagepath_dst = filepath_noext + ext
            print(f"copying texture: {imagepath!r} -> {imagepath_dst!r}")

            try:
                shutil.copy(imagepath, imagepath_dst)
            except:
                import traceback
                traceback.print_exc()


def write_mesh(context, report_cb):
    import os

    scene = context.scene
    layer = context.view_layer
    unit = scene.unit_settings
    print_3d = scene.print_3d

    export_format = print_3d.export_format
    global_scale = unit.scale_length if (unit.system != 'NONE' and print_3d.use_apply_scale) else 1.0
    path_mode = 'COPY' if print_3d.use_export_texture else 'AUTO'
    export_path = bpy.path.abspath(print_3d.export_path)
    obj = layer.objects.active
    export_data_layers = print_3d.use_data_layers

    # Create name 'export_path/blendname-objname'
    # add the filename component
    if bpy.data.is_saved:
        name = os.path.basename(bpy.data.filepath)
        name = os.path.splitext(name)[0]
    else:
        name = "untitled"

    # add object name
    name += f"-{bpy.path.clean_name(obj.name)}"

    # first ensure the path is created
    if export_path:
        # this can fail with strange errors,
        # if the dir can't be made then we get an error later.
        try:
            os.makedirs(export_path, exist_ok=True)
        except:
            import traceback
            traceback.print_exc()

    filepath = os.path.join(export_path, name)

    # ensure addon is enabled
    import addon_utils

    def addon_ensure(addon_id):
        # Enable the addon, dont change preferences.
        _default_state, loaded_state = addon_utils.check(addon_id)
        if not loaded_state:
            addon_utils.enable(addon_id, default_set=False)

    if export_format == 'STL':
        addon_ensure("io_mesh_stl")
        filepath = bpy.path.ensure_ext(filepath, ".stl")
        ret = bpy.ops.export_mesh.stl(
            filepath=filepath,
            ascii=False,
            use_mesh_modifiers=True,
            use_selection=True,
            global_scale=global_scale,
        )
    elif export_format == 'PLY':
        addon_ensure("io_mesh_ply")
        filepath = bpy.path.ensure_ext(filepath, ".ply")
        ret = bpy.ops.export_mesh.ply(
            filepath=filepath,
            use_ascii=False,
            use_mesh_modifiers=True,
            use_selection=True,
            global_scale=global_scale,
            use_normals=export_data_layers,
            use_uv_coords=export_data_layers,
            use_colors=export_data_layers,
        )
    elif export_format == 'X3D':
        addon_ensure("io_scene_x3d")
        filepath = bpy.path.ensure_ext(filepath, ".x3d")
        ret = bpy.ops.export_scene.x3d(
            filepath=filepath,
            use_mesh_modifiers=True,
            use_selection=True,
            global_scale=global_scale,
            path_mode=path_mode,
            use_normals=export_data_layers,
        )
    elif export_format == 'OBJ':
        addon_ensure("io_scene_obj")
        filepath = bpy.path.ensure_ext(filepath, ".obj")
        ret = bpy.ops.export_scene.obj(
            filepath=filepath,
            use_mesh_modifiers=True,
            use_selection=True,
            global_scale=global_scale,
            path_mode=path_mode,
            use_normals=export_data_layers,
            use_uvs=export_data_layers,
            use_materials=export_data_layers,
        )
    else:
        assert 0

    # for formats that don't support images
    if path_mode == 'COPY' and export_format in {'STL', 'PLY'}:
        image_copy_guess(filepath, context.selected_objects)

    if 'FINISHED' in ret:
        if report_cb is not None:
            report_cb({'INFO'}, f"Exported: {filepath!r}")

        return True

    if report_cb is not None:
        report_cb({'ERROR'}, "Export failed")

    return False
