# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
from bpy.types import Armature, Context, Mesh, UILayout, UIList

from ...common.logger import get_logger
from ..extension import get_armature_extension
from ..property_group import BonePropertyGroup, StringPropertyGroup
from .property_group import (
    Vrm0BlendShapeBindPropertyGroup,
    Vrm0BlendShapeGroupPropertyGroup,
    Vrm0FirstPersonPropertyGroup,
    Vrm0MaterialValueBindPropertyGroup,
    Vrm0MeshAnnotationPropertyGroup,
    Vrm0SecondaryAnimationColliderGroupPropertyGroup,
    Vrm0SecondaryAnimationColliderPropertyGroup,
    Vrm0SecondaryAnimationGroupPropertyGroup,
)

logger = get_logger(__name__)


class VRM_UL_vrm0_first_person_mesh_annotation(UIList):
    bl_idname = "VRM_UL_vrm0_first_person_mesh_annotation"

    def draw_item(
        self,
        _context: Context,
        layout: UILayout,
        first_person: object,
        mesh_annotation: object,
        _icon: int,
        _active_data: object,
        _active_prop_name: str,
        index: int,
        _flt_flag: int,
    ) -> None:
        if not isinstance(first_person, Vrm0FirstPersonPropertyGroup):
            return
        if not isinstance(mesh_annotation, Vrm0MeshAnnotationPropertyGroup):
            return

        icon = "OUTLINER_OB_MESH"

        if self.layout_type == "GRID":
            layout.alignment = "CENTER"
            layout.label(text="", translate=False, icon=icon)
            return

        if self.layout_type not in {"DEFAULT", "COMPACT"}:
            return

        row = layout.split(factor=0.6, align=True)
        if index == first_person.active_mesh_annotation_index:
            row.prop(
                mesh_annotation.mesh,
                "bpy_object",
                icon=icon,
                text="",
                translate=False,
            )
        else:
            row.label(
                text=mesh_annotation.mesh.mesh_object_name,
                translate=False,
                icon=icon,
            )
        row.prop(mesh_annotation, "first_person_flag", text="", translate=False)


class VRM_UL_vrm0_secondary_animation_group(UIList):
    bl_idname = "VRM_UL_vrm0_secondary_animation_group"

    def draw_item(
        self,
        _context: Context,
        layout: UILayout,
        _data: object,
        bone_group: object,
        _icon: int,
        _active_data: object,
        _active_prop_name: str,
        _index: int,
        _flt_flag: int,
    ) -> None:
        if not isinstance(bone_group, Vrm0SecondaryAnimationGroupPropertyGroup):
            return

        icon = "BONE_DATA"

        if self.layout_type == "GRID":
            layout.alignment = "CENTER"
            layout.label(text="", translate=False, icon=icon)
            return

        if self.layout_type not in {"DEFAULT", "COMPACT"}:
            return

        text = ""
        if bone_group.bones:
            text = (
                "(" + ", ".join(str(bone.bone_name) for bone in bone_group.bones) + ")"
            )

        if bone_group.center.bone_name:
            if text:
                text = " - " + text
            text = bone_group.center.bone_name + text

        if bone_group.comment:
            if text:
                text = " / " + text
            text = bone_group.comment + text

        if not text:
            text = "(EMPTY)"

        layout.label(text=text, translate=False, icon=icon)


class VRM_UL_vrm0_secondary_animation_group_bone(UIList):
    bl_idname = "VRM_UL_vrm0_secondary_animation_group_bone"

    def draw_item(
        self,
        _context: Context,
        layout: UILayout,
        bone_group: object,
        bone: object,
        _icon: int,
        _active_data: object,
        _active_prop_name: str,
        index: int,
        _flt_flag: int,
    ) -> None:
        if not isinstance(bone_group, Vrm0SecondaryAnimationGroupPropertyGroup):
            return
        if not isinstance(bone, BonePropertyGroup):
            return
        armature = bone.find_armature()

        icon = "BONE_DATA"

        if self.layout_type == "GRID":
            layout.alignment = "CENTER"
            layout.label(text="", translate=False, icon=icon)
            return

        if self.layout_type not in {"DEFAULT", "COMPACT"}:
            return

        if index == bone_group.active_bone_index:
            layout.prop_search(
                bone,
                "bone_name",
                armature,
                "bones",
                text="",
                translate=False,
                icon=icon,
            )
        else:
            layout.label(text=bone.bone_name, translate=False, icon=icon)


class VRM_UL_vrm0_secondary_animation_group_collider_group(UIList):
    bl_idname = "VRM_UL_vrm0_secondary_animation_group_collider_group"

    def draw_item(
        self,
        _context: Context,
        layout: UILayout,
        bone_group: object,
        collider_group: object,
        _icon: int,
        _active_data: object,
        _active_prop_name: str,
        index: int,
        _flt_flag: int,
    ) -> None:
        if not isinstance(bone_group, Vrm0SecondaryAnimationGroupPropertyGroup):
            return
        if not isinstance(collider_group, StringPropertyGroup):
            return

        armature_data = bone_group.id_data
        if not isinstance(armature_data, Armature):
            logger.error("Failed to find armature")
            return

        secondary_animation = get_armature_extension(
            armature_data
        ).vrm0.secondary_animation

        icon = "PIVOT_INDIVIDUAL"

        if self.layout_type == "GRID":
            layout.alignment = "CENTER"
            layout.label(text="", translate=False, icon=icon)
            return

        if self.layout_type not in {"DEFAULT", "COMPACT"}:
            return

        if index == bone_group.active_collider_group_index:
            layout.prop_search(
                collider_group,
                "value",
                secondary_animation,
                "collider_groups",
                text="",
                translate=False,
                icon=icon,
            )
        else:
            layout.label(text=collider_group.value, translate=False, icon=icon)


class VRM_UL_vrm0_secondary_animation_collider_group(UIList):
    bl_idname = "VRM_UL_vrm0_secondary_animation_collider_group"

    def draw_item(
        self,
        _context: Context,
        layout: UILayout,
        _data: object,
        collider_group: object,
        _icon: int,
        _active_data: object,
        _active_prop_name: str,
        _index: int,
        _flt_flag: int,
    ) -> None:
        if not isinstance(
            collider_group, Vrm0SecondaryAnimationColliderGroupPropertyGroup
        ):
            return

        icon = "SPHERE"

        if self.layout_type == "GRID":
            layout.alignment = "CENTER"
            layout.label(text="", translate=False, icon=icon)
            return

        if self.layout_type not in {"DEFAULT", "COMPACT"}:
            return

        layout.label(text=collider_group.name, translate=False, icon=icon)


class VRM_UL_vrm0_secondary_animation_collider_group_collider(UIList):
    bl_idname = "VRM_UL_vrm0_secondary_animation_collider_group_collider"

    def draw_item(
        self,
        _context: Context,
        layout: UILayout,
        collider_group: object,
        collider: object,
        _icon: int,
        _active_data: object,
        _active_prop_name: str,
        index: int,
        _flt_flag: int,
    ) -> None:
        if not isinstance(
            collider_group, Vrm0SecondaryAnimationColliderGroupPropertyGroup
        ):
            return
        if not isinstance(collider, Vrm0SecondaryAnimationColliderPropertyGroup):
            return

        icon = "MESH_UVSPHERE"

        if self.layout_type == "GRID":
            layout.alignment = "CENTER"
            layout.label(text="", translate=False, icon=icon)
            return

        if self.layout_type not in {"DEFAULT", "COMPACT"}:
            return

        bpy_object = collider.bpy_object
        if bpy_object is None:
            return

        row = layout.split(align=True, factor=0.7)
        if index == collider_group.active_collider_index:
            row.prop(
                bpy_object,
                "name",
                icon=icon,
                translate=False,
                text="",
            )
            row.prop(bpy_object, "empty_display_size", text="")
        else:
            row.label(text=bpy_object.name, icon=icon, translate=False)
            row.prop(bpy_object, "empty_display_size", text="", emboss=False)


class VRM_UL_vrm0_blend_shape_group(UIList):
    bl_idname = "VRM_UL_vrm0_blend_shape_group"

    def draw_item(
        self,
        _context: Context,
        layout: UILayout,
        _data: object,
        item: object,
        _icon: int,
        _active_data: object,
        _active_prop_name: str,
        _index: int,
        _flt_flag: int,
    ) -> None:
        blend_shape_group = item
        if not isinstance(blend_shape_group, Vrm0BlendShapeGroupPropertyGroup):
            return

        preset = next(
            (
                preset
                for preset in blend_shape_group.preset_name_enum
                if preset.identifier == blend_shape_group.preset_name
            ),
            None,
        )
        if not preset:
            return

        if self.layout_type == "GRID":
            layout.alignment = "CENTER"
            layout.label(text="", translate=False, icon=preset.icon)
            return

        if self.layout_type not in {"DEFAULT", "COMPACT"}:
            return

        text = blend_shape_group.name + " / " + preset.name
        split = layout.split(align=True, factor=0.55)
        split.label(text=text, translate=False, icon=preset.icon)
        split.prop(blend_shape_group, "preview", text="Preview")


class VRM_UL_vrm0_blend_shape_bind(UIList):
    bl_idname = "VRM_UL_vrm0_blend_shape_bind"

    def draw_item(
        self,
        context: Context,
        layout: UILayout,
        _data: object,
        item: object,
        icon: int,
        _active_data: object,
        _active_prop_name: str,
        _index: int,
        _flt_flag: int,
    ) -> None:
        blend_data = context.blend_data
        blend_shape_bind = item
        if not isinstance(blend_shape_bind, Vrm0BlendShapeBindPropertyGroup):
            return

        if self.layout_type == "GRID":
            layout.alignment = "CENTER"
            layout.label(text="", translate=False, icon_value=icon)
            return

        if self.layout_type not in {"DEFAULT", "COMPACT"}:
            return

        name = blend_shape_bind.mesh.mesh_object_name
        mesh_object = blend_data.objects.get(blend_shape_bind.mesh.mesh_object_name)
        if mesh_object:
            mesh_data = mesh_object.data
            if isinstance(mesh_data, Mesh):
                shape_keys = mesh_data.shape_keys
                if shape_keys:
                    keys = shape_keys.key_blocks.keys()
                    if blend_shape_bind.index in keys:
                        name += " / " + blend_shape_bind.index
        layout.label(text=name, translate=False, icon="MESH_DATA")


class VRM_UL_vrm0_material_value_bind(UIList):
    bl_idname = "VRM_UL_vrm0_material_value_bind"

    def draw_item(
        self,
        _context: Context,
        layout: UILayout,
        _data: object,
        item: object,
        icon: int,
        _active_data: object,
        _active_prop_name: str,
        _index: int,
        _flt_flag: int,
    ) -> None:
        material_value_bind = item
        if not isinstance(material_value_bind, Vrm0MaterialValueBindPropertyGroup):
            return

        if self.layout_type == "GRID":
            layout.alignment = "CENTER"
            layout.label(text="", translate=False, icon_value=icon)
            return

        if self.layout_type not in {"DEFAULT", "COMPACT"}:
            return

        name = ""
        material = material_value_bind.material
        if material:
            name = material.name
            if material_value_bind.property_name:
                name += " / " + material_value_bind.property_name
        layout.label(text=name, translate=False, icon="MATERIAL")
