from scrapling.core._types import Any, Dict


class SelectorsGeneration:
    """
    Functions for generating selectors
    Trying to generate selectors like Firefox or maybe cleaner ones!? Ehm
    Inspiration: https://searchfox.org/mozilla-central/source/devtools/shared/inspector/css-logic.js#591
    """

    # Note: This is a mixin class meant to be used with Selector.
    # The methods access Selector attributes (._root, .parent, .attrib, .tag, etc.)
    # through self, which will be a Selector instance at runtime.

    def _general_selection(self: Any, selection: str = "css", full_path: bool = False) -> str:
        """Generate a selector for the current element.
        :return: A string of the generated selector.
        """
        if self._is_text_node(self._root):
            return ""

        selectorPath = []
        target = self
        css = selection.lower() == "css"
        while target is not None:
            if target.parent:
                if target.attrib.get("id"):
                    # id is enough
                    if css:
                        part = f"#{target.attrib['id']}"
                    elif full_path:
                        part = f"*[@id='{target.attrib['id']}']"
                    else:
                        part = f"[@id='{target.attrib['id']}']"
                    selectorPath.append(part)
                    if not full_path:
                        return " > ".join(reversed(selectorPath)) if css else "//*" + "/".join(reversed(selectorPath))
                else:
                    part = f"{target.tag}"
                    # We won't use classes anymore because I some websites share exact classes between elements
                    # classes = target.attrib.get('class', '').split()
                    # if classes and css:
                    #     part += f".{'.'.join(classes)}"
                    # else:
                    counter: Dict[str, int] = {}
                    for child in target.parent.children:
                        counter.setdefault(child.tag, 0)
                        counter[child.tag] += 1
                        if child._root == target._root:
                            break

                    if counter[target.tag] > 1:
                        part += f":nth-of-type({counter[target.tag]})" if css else f"[{counter[target.tag]}]"

                    selectorPath.append(part)
                target = target.parent
                if target is None or target.tag == "html":
                    return " > ".join(reversed(selectorPath)) if css else "//" + "/".join(reversed(selectorPath))
            else:
                break

        return " > ".join(reversed(selectorPath)) if css else "//" + "/".join(reversed(selectorPath))

    @property
    def generate_css_selector(self: Any) -> str:
        """Generate a CSS selector for the current element
        :return: A string of the generated selector.
        """
        return self._general_selection()

    @property
    def generate_full_css_selector(self: Any) -> str:
        """Generate a complete CSS selector for the current element
        :return: A string of the generated selector.
        """
        return self._general_selection(full_path=True)

    @property
    def generate_xpath_selector(self: Any) -> str:
        """Generate an XPath selector for the current element
        :return: A string of the generated selector.
        """
        return self._general_selection("xpath")

    @property
    def generate_full_xpath_selector(self: Any) -> str:
        """Generate a complete XPath selector for the current element
        :return: A string of the generated selector.
        """
        return self._general_selection("xpath", full_path=True)
