"""Functions for manipulating object data."""

import bmesh
import bpy
from bpy.types import Context, Object


def flatten_object_hierarchy(objects: list[Object]) -> dict[Object, Object]:
    """Flatten the object hierarchy of the given list of objects.

    Objects may not appear properly in RizomUV in some parent/child
    setups. Easiest solution is to flatten the hierarchy and restore
    it after export.

    Args:
    ----
        objects: Hierarchy of objects to flatten.

    Returns:
    -------
        Map of objects to original parents allowing restoration later.

    """
    object_relationships = {}
    for obj in objects:
        object_relationships[obj] = obj.parent

        # Important to keep transforms
        if obj.parent is not None:
            bpy.context.view_layer.objects.active = obj
            bpy.ops.object.parent_clear(type="CLEAR_KEEP_TRANSFORM")

    return object_relationships


def replace_illegal_chars(obj: Object):
    """Replace illegal characters in object name with underscores.

    Args:
    ----
        obj: Object to rename.

    """
    obj.name = obj.name.replace(" ", "_")


def apply_modifiers(objects: list[Object]):
    """Apply all modifiers to the given objects.

    Args:
    ----
        objects: List of objects to apply modifiers to.

    """
    for obj in objects:
        bpy.context.view_layer.objects.active = obj
        for mod in obj.modifiers:
            bpy.ops.object.modifier_apply(modifier=mod.name)


def triangulate_objects(objects: list[Object]):
    """Triangulate all objects in the list.

    - Must be in object mode

    Args:
    ----
        objects: List of objects to triangulate.

    """
    for obj in objects:
        bm = bmesh.new()
        bm.from_mesh(obj.data)
        bmesh.ops.triangulate(bm, faces=bm.faces)
        bm.select_flush(True)
        bm.to_mesh(obj.data)


def unwrap_objects(context: Context, objects: list[Object], target_uvmap: str):
    """Pre-unwrap all objects in the list using seams.

    Allows user to create UV cuts in Blender before exporting to Rizom.

    Args:
    ----
        context: Blender context.
        objects: List of objects to preunwrap.
        target_uvmap: Name of UV map to unwrap.

    """
    view_layer = context.view_layer
    active_obj = context.active_object
    original_uvmap_selection = active_obj.data.uv_layers.active

    bpy.ops.object.select_all(action="DESELECT")

    for obj in objects:
        active_map = obj.data.uv_layers[target_uvmap]
        view_layer.objects.active = obj
        bpy.ops.object.mode_set(mode="EDIT")
        obj.data.uv_layers.active = active_map
        bpy.ops.uv.select_all(action="SELECT")
        bpy.ops.uv.weld()
        bpy.ops.mesh.select_all(action="SELECT")
        bpy.ops.uv.unwrap(margin=0.01)

    # Restore selection state
    bpy.ops.object.mode_set(mode="OBJECT")
    for obj in objects:
        obj.select_set(True)
        obj.data.uv_layers.active = original_uvmap_selection

    view_layer.objects.active = active_obj
