
__all__ = ["PropertyWidgetBuilder"]

import omni.ui as ui

LABEL_HEIGHT = 18
HORIZONTAL_SPACING = 4
LABEL_WIDTH = 150


class PropertyWidgetBuilder:
    @classmethod
    def _build_reset_button(cls, path) -> ui.Rectangle:
        with ui.VStack(width=0, height=0):
            ui.Spacer()
            with ui.ZStack(width=15, height=15):
                with ui.HStack(style={"margin_width": 0}):
                    ui.Spacer()
                    with ui.VStack(width=0):
                        ui.Spacer()
                        ui.Rectangle(width=5, height=5, name="reset_invalid")
                        ui.Spacer()
                    ui.Spacer()
                btn = ui.Rectangle(width=12, height=12, name="reset", tooltip="Click to reset value")
                btn.visible = False

            btn.set_mouse_pressed_fn(lambda x, y, m, w, p=path, b=btn: cls._restore_defaults(path, b))
            ui.Spacer()

        return btn

    @staticmethod
    def _create_multi_float_drag_with_labels(model, labels, comp_count, **kwargs) -> None:
        RECT_WIDTH = 13
        SPACING = 4
        with ui.ZStack():
            with ui.HStack():
                ui.Spacer(width=RECT_WIDTH)
                widget_kwargs = {"name": "multivalue", "h_spacing": RECT_WIDTH + SPACING}
                widget_kwargs.update(kwargs)
                ui.MultiFloatDragField(model, **widget_kwargs)
            with ui.HStack():
                for i in range(comp_count):
                    if i != 0:
                        ui.Spacer(width=SPACING)
                    label = labels[i]
                    with ui.ZStack(width=RECT_WIDTH + 1):
                        ui.Rectangle(name="vector_label", style={"background_color": label[1]})
                        ui.Label(label[0], name="vector_label", alignment=ui.Alignment.CENTER)
                    ui.Spacer()

    @classmethod
    def createColorWidget(cls, model, comp_count=3, additional_widget_kwargs=None) -> ui.HStack:
        with ui.HStack(spacing=HORIZONTAL_SPACING) as widget:
            widget_kwargs = {"min": 0.0, "max": 1.0}
            if additional_widget_kwargs:
                widget_kwargs.update(additional_widget_kwargs)

            # TODO probably need to support "A" if comp_count is 4, but how many assumptions can we make?
            with ui.HStack(spacing=4):
                cls._create_multi_float_drag_with_labels(
                    model=model,
                    labels=[("R", 0xFF5555AA), ("G", 0xFF76A371), ("B", 0xFFA07D4F)],
                    comp_count=comp_count,
                    **widget_kwargs,
                )
                widget = ui.ColorWidget(model, width=30, height=0)
            # cls._create_control_state(model)
        return widget

    @classmethod
    def createVecWidget(cls, model, range_min, range_max, comp_count=3, additional_widget_kwargs=None):
        widget_kwargs = {"min": range_min, "max": range_max}
        if additional_widget_kwargs:
            widget_kwargs.update(additional_widget_kwargs)
        cls._create_multi_float_drag_with_labels(
            model=model,
            labels=[("X", 0xFF5555AA), ("Y", 0xFF76A371), ("Z", 0xFFA07D4F), ("W", 0xFFFFFFFF)],
            comp_count=comp_count,
            **widget_kwargs,
        )
        return model

    @staticmethod
    def _create_drag_or_slider(drag_widget, slider_widget, **kwargs):
        if "min" in kwargs and "max" in kwargs:
            range_min = kwargs["min"]
            range_max = kwargs["max"]
            if range_max - range_min < 100:
                return slider_widget(name="value", **kwargs)
            else:
                if "step" not in kwargs:
                    kwargs["step"] = max(0.1, (range_max - range_min) / 1000.0)
        else:
            if "step" not in kwargs:
                kwargs["step"] = 0.1

        # If range is too big or no range, don't use a slider
        widget = drag_widget(name="value", **kwargs)
        return widget

    @classmethod
    def _create_label(cls, attr_name, label_width=150, additional_label_kwargs=None):
        label_kwargs = {
            "name": "label",
            "word_wrap": True,
            "width": label_width,
            "height": LABEL_HEIGHT,
            "alignment": ui.Alignment.LEFT,
        }

        if additional_label_kwargs:
            label_kwargs.update(additional_label_kwargs)
        ui.Label(attr_name, **label_kwargs)
        ui.Spacer(width=5)

    @classmethod
    def createBoolWidget(cls, model, additional_widget_kwargs=None):
        widget = None
        with ui.HStack():
            with ui.HStack(style={"margin_width": 0}, width=10):
                ui.Spacer()
                widget_kwargs = {"font_size": 16, "height": 16, "width": 16, "model": model}
                if additional_widget_kwargs:
                    widget_kwargs.update(additional_widget_kwargs)
                widget = ui.CheckBox(**widget_kwargs, style={"color": 0xFFDDDDDD, "background_color": 0xFF666666})
                ui.Spacer()
        return widget

    @classmethod
    def createFloatWidget(cls, model, range_min, range_max, additional_widget_kwargs=None):
        widget_kwargs = {"model": model}
        # only set range if range is valid (min < max)
        if range_min < range_max:
            widget_kwargs["min"] = range_min
            widget_kwargs["max"] = range_max
        if additional_widget_kwargs:
            widget_kwargs.update(additional_widget_kwargs)
        widget_kwargs.update(style={"secondary_color": 0xFF444444})
        return cls._create_drag_or_slider(ui.FloatDrag, ui.FloatSlider, **widget_kwargs)

    @classmethod
    def createIntWidget(cls, model, range_min, range_max, additional_widget_kwargs=None):
        widget_kwargs = {"model": model}  # This passes the model into the widget
        # only set range if range is valid (min < max)
        if range_min < range_max:
            widget_kwargs["min"] = range_min
            widget_kwargs["max"] = range_max
        if additional_widget_kwargs:
            widget_kwargs.update(additional_widget_kwargs)
        widget_kwargs.update(style={"secondary_color": 0xFF444444})

        return cls._create_drag_or_slider(ui.IntDrag, ui.IntSlider, **widget_kwargs)
