import asyncio
import omni.kit.app
import omni.ui as ui
from enum import IntFlag


class SearchModel(ui.AbstractValueModel):
    def __init__(self, modified_fn):
        super().__init__()
        self._modified_fn = modified_fn
        self.__str = ""

    def is_in_string(self, string: str):
        if self.__str == "":
            return True
        return self.__str.upper() in string.upper()

    def set_value(self, value):
        self.__str = str(value)
        self._value_changed()
        if self._modified_fn:
            self._modified_fn(self.__str)

    def get_value_as_string(self):
        return self.__str


class SearchWidget:
    def __init__(self, theme: str, icon_path: str, modified_fn: callable = None):
        self._search_model = SearchModel(modified_fn=modified_fn)
        if not icon_path:
            icon_path = (
                f"{omni.kit.app.get_app().get_extension_manager().get_extension_path_by_module(__name__)}/data/icons"
            )

        if theme == "NvidiaDark":
            SEARCH_BODY_COLOR = 0xFF2D2D2D
            SEARCH_PLACEHOLDER = 0xFF666666
            BUTTON_BACKGROUND_COLOR = 0xFF323434
            COMBO_BACKGROUND_COLOR = 0xFF92929
            GENERAL_BACKGROUND_COLOR = 0xFF24211F
        else:
            SEARCH_BODY_COLOR = 0xFF2D2D2D
            SEARCH_PLACEHOLDER = 0xFF666666
            BUTTON_BACKGROUND_COLOR = 0xFF545454
            COMBO_BACKGROUND_COLOR = 0xFF545454
            GENERAL_BACKGROUND_COLOR = 0xFF545454

        self._style = {
            # search_button
            "Button.Image::search_button": {
                "image_url": f"{icon_path}/search.svg",
                "background_color": SEARCH_BODY_COLOR,
                "margin": 0,
            },
            "Button::search_button": {"margin": 0},
            "Field::search_button": {"background_color": SEARCH_BODY_COLOR},
            "Field::search_button:hovered": {"background_color": SEARCH_BODY_COLOR},
            # search placeholder
            "Label::search_placeholder": {"color": SEARCH_PLACEHOLDER},
            # remove button
            "Button.Image::remove": {"image_url": f"{icon_path}/remove.svg"},
            "Button.Image::remove:hovered": {"image_url": f"{icon_path}/remove-hovered.svg"},
            "Button::remove": {"background_color": SEARCH_BODY_COLOR, "margin": 0},
            "Button::remove:hovered": {"background_color": SEARCH_BODY_COLOR, "margin": 0},
            # remove button popup (different colors)
            "Button::remove_popup": {"background_color": GENERAL_BACKGROUND_COLOR, "margin": 0},
            "Button::remove_popup:hovered": {"background_color": GENERAL_BACKGROUND_COLOR, "margin": 0},
            "Button.Image::remove_popup": {"image_url": f"{icon_path}/remove.svg"},
            "Button.Image::remove_popup:hovered": {"image_url": f"{icon_path}/remove-hovered.svg"},
            # find button
            "Button::find": {"background_color": BUTTON_BACKGROUND_COLOR},
            "Button.Image::find": {"image_url": f"{icon_path}/find.svg"},
            # listbox button
            "Button.Image::listbox": {"image_url": f"{icon_path}/listbox.svg"},
            "Button::listbox": {"background_color": COMBO_BACKGROUND_COLOR, "padding": 6, "margin": 0},
        }

    def clean(self):
        self._field = None
        self._search_field = None
        self._search_clear = None
        self._update_fn = None

    def destroy(self):
        self._field = None
        self._search_field = None
        self._search_clear = None
        self._update_fn = None
        del self._search_model

    def update(self, string):
        self._placeholder.visible = bool(string == "")
        self._search_clear.enabled = not self._placeholder.visible

    def focus(self):
        async def focus(field):
            await omni.kit.app.get_app().next_update_async()
            field.focus_keyboard()

        asyncio.ensure_future(focus(self._field))

    def build_ui(self, width, search_size):
        def clear_name(field):
            field.model.set_value("")
            field.focus_keyboard()

        with ui.HStack(width=0, height=0, style=self._style):
            ui.Button("", width=search_size, height=search_size, enabled=False, name="search_button")
            with ui.ZStack(width=0, height=0):
                with ui.HStack(width=0, height=0):
                    field = ui.StringField(
                        model=self._search_model, width=width - 46, height=search_size, name="search_button"
                    )
                    self._search_clear = ui.Button(
                        "",
                        width=search_size,
                        height=search_size,
                        fill_policy=ui.FillPolicy.PRESERVE_ASPECT_FIT,
                        enabled=False,
                        clicked_fn=lambda f=field: clear_name(f),
                        name="remove",
                    )
                self._placeholder = ui.Label("  Search....", height=search_size, name="search_placeholder")
                self._field = field
                self.focus()

    def set_placeholder_text(self, msg: str):
        self._placeholder.text = f"  {msg}...."
        enabled = bool(msg == "Search")
        self._field.enabled = enabled
        self._field.focus_keyboard(enabled)

    def set_text(self, new_text: str):
        changed = bool(self._search_field.model.get_value_as_string() != new_text)
        self._search_field.model.set_value(new_text)
        if changed and self._update_fn:
            self._update_fn(self._search_field.model)

    def get_text(self):
        return self._search_field.model.get_value_as_string()

    def build_ui_popup(self, search_size: float, default_value: str, popup_text: str, index: int, update_fn: callable):
        def clear_name(name_field):
            name_field.model.set_value(default_value)
            if update_fn:
                update_fn(name_field.model)

        self._update_fn = update_fn
        open_button = None
        name_field = None

        with omni.ui.VStack(height=0, spacing=0, style={"margin_width": 0}):
            with ui.HStack(style=self._style):
                name_field = ui.StringField(height=search_size, enabled=False)
                name_field.model.set_value(popup_text)

                ui.Button(
                    "",
                    width=20,
                    height=20,
                    fill_policy=ui.FillPolicy.PRESERVE_ASPECT_FIT,
                    clicked_fn=lambda f=name_field: clear_name(f),
                    name="remove_popup",
                )

                open_button = ui.Button("", width=20, height=20, image_width=8, name="listbox")

        self._search_field = name_field
        return name_field, open_button
