import carb
import math
from omni import ui
from typing import Optional, Dict
from .style import UI_STYLE


def split_selection(text, selection, match_case: bool = False):
    """
    Split given text to substrings to draw selected text. Result starts with unselected text.
    Example: "helloworld" "o" -> ["hell", "o", "w", "o", "rld"]
    Example: "helloworld" "helloworld" -> ["", "helloworld"]
    """
    if not selection:
        return [text, ""]
    else:
        origin_text = text
        if not match_case:
            selection = selection.lower()
            text = text.lower()
        elif text == selection:
            return ["", text]

    selection_len = len(selection)
    result = []
    while True:
        found = text.find(selection)

        result.append(origin_text if found < 0 else origin_text[:found])

        if found < 0:
            break
        else:
            result.append(origin_text[found : found + selection_len])
            text = text[found + selection_len :]
            origin_text = origin_text[found + selection_len :]

    return result


class HighlightLabel:
    """
    Represents a label widget could show hightlight word.
    Args:
        text (str): String of label.

    Keyword args:
        highlight (Optional[str]): Word to show highlight
        match_case (bool): Show highlight word with case sensitive. Default False.
        width (ui.Length): Widget length. Default ui.Fraction(1)
        height (ui.Length): Widget height. Default 0
        style (Dict): Custom style
    """

    def __init__(
        self,
        text: str,
        highlight: Optional[str] = None,
        match_case: bool = False,
        width: ui.Length=ui.Fraction(1),
        height: ui.Length=0,
        style: Dict = {}
    ):
        self._container: Optional[ui.HStack] = None
        self.__text = text
        self.__hightlight = highlight
        self.__match_case = match_case
        self.__width = width
        self.__height = height
        self.__style = UI_STYLE.copy()
        self.__style.update(style)
        self._build_ui()

    def _build_ui(self):
        if not self._container:
            self._container = ui.HStack(width=self.__width, height=self.__height, style=self.__style)
        else:
            self._container.clear()

        if not self.__hightlight:
            with self._container:
                ui.Label(
                    self.__text,
                    width=0,
                    name="",
                    style_type_name_override="HighlightLabel",
                )
        else:
            selection_chain = split_selection(self.__text, self.__hightlight, match_case=self.__match_case)
            labelnames_chain = ["", "highlight"]
            # Extend the label names depending on the size of the selection chain. Example, if it was [a, b]
            # and selection_chain is [z,y,x,w], it will become [a, b, a, b].
            labelnames_chain *= int(math.ceil(len(selection_chain) / len(labelnames_chain)))

            with self._container:
                for current_text, current_name in zip(selection_chain, labelnames_chain):
                    if not current_text:
                        continue

                    ui.Label(
                        current_text,
                        width=0,
                        name=current_name,
                        style_type_name_override="HighlightLabel",
                    )

    @property
    def widget(self) -> Optional[ui.HStack]:
        return self._container

    @property
    def visible(self) -> None:
        """
        Widget visibility
        """
        return self._container.visible

    @visible.setter
    def visible(self, value: bool) -> None:
        self._container.visible = value

    @property
    def text(self) -> str:
        return self.__text

    @text.setter
    def text(self, value: str) -> None:
        self.__text = value
        self._build_ui()

    @property
    def hightlight(self) -> Optional[str]:
        return self.__hightlight

    @hightlight.setter
    def highlight(self, value: Optional[str]) -> None:
        self.__hightlight = value
        self._build_ui()

    @property
    def text(self) -> str:
        return self.__text

    @text.setter
    def text(self, value: str) -> None:
        self.__text = value