"""
相对定位器 - 支持 DOM 相对定位

提供基于已定位元素查找其父/子/兄弟等相对元素的能力。

示例:
    async with EasyBrowser() as browser:
        # 获取父元素
        card = browser('div.card')
        parent = card.parent()

        # 获取子元素
        button = card.child('button.submit')

        # 获取兄弟元素
        next_item = card.next_sibling('div.card')
        prev_item = card.prev_sibling()

        # 获取祖先元素
        form = browser('input').ancestor('form')

        # 获取附近元素（基于位置）
        nearby = browser('button').near('span.tooltip', max_distance=100)
"""
from typing import Optional, TYPE_CHECKING
from playwright.async_api import Locator, Page

if TYPE_CHECKING:
    from .element import Element


class RelativeLocator:
    """
    相对定位器

    支持基于当前元素的 DOM 相对定位。
    """

    def __init__(self, locator: Locator, page: Page):
        """
        初始化相对定位器

        Args:
            locator: 当前元素的 Locator
            page: Page 对象
        """
        self._locator = locator
        self._page = page

    def parent(self, level: int = 1) -> "Element":
        """
        获取父元素

        Args:
            level: 向上层级（默认1为直接父元素）

        Returns:
            Element: 父元素

        Example:
            parent = element.parent()
            grandparent = element.parent(2)
        """
        from .element import Element

        if level < 1:
            raise ValueError("level 必须 >= 1")

        # 使用 XPath 的祖先轴定位
        xpath = "/".join([".."] * level)
        parent_locator = self._locator.locator(f"xpath={xpath}")

        return Element(parent_locator, self._page, f"parent(level={level})")

    def child(
        self,
        selector: Optional[str] = None,
        index: int = 0,
    ) -> "Element":
        """
        获取子元素

        Args:
            selector: 子元素选择器（可选，默认获取所有子元素）
            index: 子元素索引（从 0 开始）

        Returns:
            Element: 子元素

        Example:
            first_child = element.child()
            second_child = element.child(index=1)
            button = element.child('button')
        """
        from .element import Element

        if selector:
            # 检测选择器类型
            if selector.startswith("//") or selector.startswith(".//"):
                # XPath 选择器
                child_locator = self._locator.locator(f"xpath={selector}")
            elif selector.startswith("text=") or selector.startswith("t:"):
                # 文本选择器
                text = selector.replace("text=", "").replace("t:", "")
                child_locator = self._locator.get_by_text(text)
            else:
                # CSS 选择器
                child_locator = self._locator.locator(selector)
        else:
            # 获取所有直接子元素
            child_locator = self._locator.locator("xpath=child::*")

        return Element(
            child_locator.nth(index),
            self._page,
            f"child(selector='{selector}', index={index})"
        )

    def children(self, selector: Optional[str] = None) -> "Element":
        """
        获取所有子元素

        Args:
            selector: 子元素选择器（可选）

        Returns:
            Element: 子元素列表

        Example:
            all_children = element.children()
            all_buttons = element.children('button')
        """
        from .element import Element

        if selector:
            if selector.startswith("//") or selector.startswith(".//"):
                child_locator = self._locator.locator(f"xpath={selector}")
            else:
                child_locator = self._locator.locator(selector)
        else:
            child_locator = self._locator.locator("xpath=child::*")

        return Element(child_locator, self._page, f"children(selector='{selector}')")

    def sibling(
        self,
        selector: Optional[str] = None,
        direction: str = "next",
    ) -> "Element":
        """
        获取兄弟元素

        Args:
            selector: 兄弟元素选择器（可选）
            direction: 方向 (next/prev)

        Returns:
            Element: 兄弟元素

        Example:
            next_sibling = element.sibling()
            prev_sibling = element.sibling(direction='prev')
            next_div = element.sibling('div', direction='next')
        """
        from .element import Element

        if direction not in ("next", "prev"):
            raise ValueError("direction 必须是 'next' 或 'prev'")

        if selector:
            if selector.startswith("//") or selector.startswith(".//"):
                xpath_axis = "following-sibling" if direction == "next" else "preceding-sibling"
                sibling_locator = self._locator.locator(
                    f"xpath={xpath_axis}::{selector.lstrip('./')}"
                )
            else:
                # CSS 使用 + 或 ~ 选择器
                # 注意：Playwright 原生支持有限，这里用 XPath 替代
                xpath_axis = "following-sibling" if direction == "next" else "preceding-sibling"
                # 转换简单 CSS 选择器为 XPath
                xpath_selector = self._css_to_xpath(selector)
                sibling_locator = self._locator.locator(
                    f"xpath={xpath_axis}::{xpath_selector}"
                )
        else:
            # 获取相邻的兄弟元素
            xpath_axis = "following-sibling" if direction == "next" else "preceding-sibling"
            sibling_locator = self._locator.locator(f"xpath={xpath_axis}::*[1]")

        return Element(
            sibling_locator.first,
            self._page,
            f"sibling(selector='{selector}', direction='{direction}')"
        )

    def next_sibling(self, selector: Optional[str] = None) -> "Element":
        """
        获取下一个兄弟元素

        Args:
            selector: 兄弟元素选择器（可选）

        Returns:
            Element: 下一个兄弟元素
        """
        return self.sibling(selector, "next")

    def prev_sibling(self, selector: Optional[str] = None) -> "Element":
        """
        获取上一个兄弟元素

        Args:
            selector: 兄弟元素选择器（可选）

        Returns:
            Element: 上一个兄弟元素
        """
        return self.sibling(selector, "prev")

    def next_siblings(self, selector: Optional[str] = None) -> "Element":
        """
        获取所有后续兄弟元素

        Args:
            selector: 兄弟元素选择器（可选）

        Returns:
            Element: 后续兄弟元素列表
        """
        from .element import Element

        if selector:
            xpath_selector = self._css_to_xpath(selector) if not selector.startswith("//") else selector.lstrip("./")
            sibling_locator = self._locator.locator(f"xpath=following-sibling::{xpath_selector}")
        else:
            sibling_locator = self._locator.locator("xpath=following-sibling::*")

        return Element(sibling_locator, self._page, f"next_siblings(selector='{selector}')")

    def prev_siblings(self, selector: Optional[str] = None) -> "Element":
        """
        获取所有前面的兄弟元素

        Args:
            selector: 兄弟元素选择器（可选）

        Returns:
            Element: 前面的兄弟元素列表
        """
        from .element import Element

        if selector:
            xpath_selector = self._css_to_xpath(selector) if not selector.startswith("//") else selector.lstrip("./")
            sibling_locator = self._locator.locator(f"xpath=preceding-sibling::{xpath_selector}")
        else:
            sibling_locator = self._locator.locator("xpath=preceding-sibling::*")

        return Element(sibling_locator, self._page, f"prev_siblings(selector='{selector}')")

    def ancestor(self, selector: str) -> "Element":
        """
        获取祖先元素

        Args:
            selector: 祖先元素选择器

        Returns:
            Element: 祖先元素

        Example:
            form = input.ancestor('form')
            container = button.ancestor('div.container')
        """
        from .element import Element

        if selector.startswith("//"):
            # 已经是 XPath
            xpath_selector = selector.lstrip("./")
        else:
            # CSS 转 XPath
            xpath_selector = self._css_to_xpath(selector)

        # 使用 ancestor 轴查找最近的匹配祖先
        ancestor_locator = self._locator.locator(f"xpath=ancestor::{xpath_selector}[1]")

        return Element(ancestor_locator, self._page, f"ancestor(selector='{selector}')")

    def descendant(self, selector: str) -> "Element":
        """
        获取后代元素

        Args:
            selector: 后代元素选择器

        Returns:
            Element: 后代元素

        Example:
            button = container.descendant('button.submit')
        """
        from .element import Element

        if selector.startswith("//"):
            xpath_selector = selector.lstrip("./")
            descendant_locator = self._locator.locator(f"xpath=.//{xpath_selector}")
        else:
            descendant_locator = self._locator.locator(selector)

        return Element(descendant_locator, self._page, f"descendant(selector='{selector}')")

    async def near(
        self,
        selector: str,
        max_distance: int = 50,
    ) -> Optional["Element"]:
        """
        获取附近元素（基于位置）

        通过计算元素位置，找到距离当前元素最近的匹配元素。

        Args:
            selector: 目标元素选择器
            max_distance: 最大距离（像素）

        Returns:
            Element: 最近的元素，如果没有找到则返回 None

        Example:
            tooltip = button.near('span.tooltip', max_distance=100)
        """
        from .element import Element

        # 获取当前元素的位置
        try:
            current_box = await self._locator.bounding_box()
            if not current_box:
                return None

            current_x = current_box["x"] + current_box["width"] / 2
            current_y = current_box["y"] + current_box["height"] / 2
        except Exception:
            return None

        # 查找所有匹配的候选元素
        candidates = self._page.locator(selector)
        count = await candidates.count()

        closest_element = None
        closest_distance = float("inf")

        for i in range(count):
            try:
                candidate = candidates.nth(i)
                box = await candidate.bounding_box()
                if not box:
                    continue

                # 计算中心点
                candidate_x = box["x"] + box["width"] / 2
                candidate_y = box["y"] + box["height"] / 2

                # 计算距离
                distance = (
                    (current_x - candidate_x) ** 2 +
                    (current_y - candidate_y) ** 2
                ) ** 0.5

                if distance < closest_distance and distance <= max_distance:
                    closest_distance = distance
                    closest_element = candidate
            except Exception:
                continue

        if closest_element:
            return Element(
                closest_element,
                self._page,
                f"near(selector='{selector}', max_distance={max_distance})"
            )

        return None

    def following(self, selector: Optional[str] = None) -> "Element":
        """
        获取文档顺序中后面的元素

        Args:
            selector: 元素选择器（可选）

        Returns:
            Element: 后面的元素
        """
        from .element import Element

        if selector:
            xpath_selector = self._css_to_xpath(selector) if not selector.startswith("//") else selector.lstrip("./")
            locator = self._locator.locator(f"xpath=following::{xpath_selector}")
        else:
            locator = self._locator.locator("xpath=following::*[1]")

        return Element(locator.first, self._page, f"following(selector='{selector}')")

    def preceding(self, selector: Optional[str] = None) -> "Element":
        """
        获取文档顺序中前面的元素

        Args:
            selector: 元素选择器（可选）

        Returns:
            Element: 前面的元素
        """
        from .element import Element

        if selector:
            xpath_selector = self._css_to_xpath(selector) if not selector.startswith("//") else selector.lstrip("./")
            locator = self._locator.locator(f"xpath=preceding::{xpath_selector}")
        else:
            locator = self._locator.locator("xpath=preceding::*[1]")

        return Element(locator.first, self._page, f"preceding(selector='{selector}')")

    # ==================== 辅助方法 ====================

    def _css_to_xpath(self, css_selector: str) -> str:
        """
        将简单 CSS 选择器转换为 XPath

        仅支持基本转换，复杂选择器建议直接使用 XPath。

        Args:
            css_selector: CSS 选择器

        Returns:
            str: XPath 表达式
        """
        # 处理 ID 选择器
        if css_selector.startswith("#"):
            return f"*[@id='{css_selector[1:]}']"

        # 处理 class 选择器
        if css_selector.startswith("."):
            return f"*[contains(@class, '{css_selector[1:]}')]"

        # 处理属性选择器 [attr=value]
        if "[" in css_selector:
            import re
            # 提取标签和属性
            match = re.match(r"(\w+)?\[([^\]]+)\]", css_selector)
            if match:
                tag = match.group(1) or "*"
                attr_part = match.group(2)
                if "=" in attr_part:
                    attr, value = attr_part.split("=", 1)
                    value = value.strip("'\"")
                    return f"{tag}[@{attr}='{value}']"
                else:
                    return f"{tag}[@{attr_part}]"

        # 简单标签选择器
        return css_selector

    def __repr__(self) -> str:
        return f"<RelativeLocator>"
