"""
断言库增强
提供更丰富的断言方法
"""
from typing import Optional, Any, List, Dict, Union
from playwright.async_api import Page, Locator
from loguru import logger
import re


class Assert:
    """
    断言库
    提供流畅的链式断言API
    """
    
    def __init__(self, page: Page):
        self.page = page
        self._last_result: Optional[bool] = None
        self._last_error: Optional[str] = None
    
    # ==================== 页面断言 ====================
    
    async def url_equals(self, expected: str) -> "Assert":
        """断言URL相等"""
        actual = self.page.url
        if actual != expected:
            self._last_result = False
            self._last_error = f"URL不匹配: 期望 '{expected}', 实际 '{actual}'"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def url_contains(self, text: str) -> "Assert":
        """断言URL包含"""
        actual = self.page.url
        if text not in actual:
            self._last_result = False
            self._last_error = f"URL不包含 '{text}': {actual}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def url_matches(self, pattern: str) -> "Assert":
        """断言URL匹配正则"""
        actual = self.page.url
        if not re.search(pattern, actual):
            self._last_result = False
            self._last_error = f"URL不匹配 '{pattern}': {actual}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def title_equals(self, expected: str) -> "Assert":
        """断言标题相等"""
        actual = await self.page.title()
        if actual != expected:
            self._last_result = False
            self._last_error = f"标题不匹配: 期望 '{expected}', 实际 '{actual}'"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def title_contains(self, text: str) -> "Assert":
        """断言标题包含"""
        actual = await self.page.title()
        if text not in actual:
            self._last_result = False
            self._last_error = f"标题不包含 '{text}': {actual}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    # ==================== 元素断言 ====================
    
    async def element_exists(self, selector: str) -> "Assert":
        """断言元素存在"""
        count = await self.page.locator(selector).count()
        if count == 0:
            self._last_result = False
            self._last_error = f"元素不存在: {selector}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def element_not_exists(self, selector: str) -> "Assert":
        """断言元素不存在"""
        count = await self.page.locator(selector).count()
        if count > 0:
            self._last_result = False
            self._last_error = f"元素存在（预期不存在）: {selector}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def element_visible(self, selector: str) -> "Assert":
        """断言元素可见"""
        locator = self.page.locator(selector)
        if not await locator.is_visible():
            self._last_result = False
            self._last_error = f"元素不可见: {selector}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def element_hidden(self, selector: str) -> "Assert":
        """断言元素隐藏"""
        locator = self.page.locator(selector)
        if await locator.is_visible():
            self._last_result = False
            self._last_error = f"元素可见（预期隐藏）: {selector}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def element_enabled(self, selector: str) -> "Assert":
        """断言元素可用"""
        locator = self.page.locator(selector)
        if not await locator.is_enabled():
            self._last_result = False
            self._last_error = f"元素禁用: {selector}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def element_disabled(self, selector: str) -> "Assert":
        """断言元素禁用"""
        locator = self.page.locator(selector)
        if await locator.is_enabled():
            self._last_result = False
            self._last_error = f"元素可用（预期禁用）: {selector}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def element_checked(self, selector: str) -> "Assert":
        """断言复选框已选中"""
        locator = self.page.locator(selector)
        if not await locator.is_checked():
            self._last_result = False
            self._last_error = f"复选框未选中: {selector}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def element_unchecked(self, selector: str) -> "Assert":
        """断言复选框未选中"""
        locator = self.page.locator(selector)
        if await locator.is_checked():
            self._last_result = False
            self._last_error = f"复选框已选中（预期未选中）: {selector}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def element_focused(self, selector: str) -> "Assert":
        """断言元素获得焦点"""
        locator = self.page.locator(selector)
        if not await locator.is_focused():
            self._last_result = False
            self._last_error = f"元素未获得焦点: {selector}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    # ==================== 文本断言 ====================
    
    async def text_equals(self, selector: str, expected: str) -> "Assert":
        """断言文本相等"""
        actual = await self.page.locator(selector).text_content()
        actual = (actual or "").strip()
        if actual != expected:
            self._last_result = False
            self._last_error = f"文本不匹配: 期望 '{expected}', 实际 '{actual}'"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def text_contains(self, selector: str, text: str) -> "Assert":
        """断言文本包含"""
        actual = await self.page.locator(selector).text_content()
        actual = actual or ""
        if text not in actual:
            self._last_result = False
            self._last_error = f"文本不包含 '{text}': {actual[:100]}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def text_matches(self, selector: str, pattern: str) -> "Assert":
        """断言文本匹配正则"""
        actual = await self.page.locator(selector).text_content()
        actual = actual or ""
        if not re.search(pattern, actual):
            self._last_result = False
            self._last_error = f"文本不匹配 '{pattern}': {actual[:100]}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def text_empty(self, selector: str) -> "Assert":
        """断言文本为空"""
        actual = await self.page.locator(selector).text_content()
        actual = (actual or "").strip()
        if actual:
            self._last_result = False
            self._last_error = f"文本不为空: {actual[:50]}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def text_not_empty(self, selector: str) -> "Assert":
        """断言文本不为空"""
        actual = await self.page.locator(selector).text_content()
        actual = (actual or "").strip()
        if not actual:
            self._last_result = False
            self._last_error = "文本为空"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    # ==================== 值断言 ====================
    
    async def value_equals(self, selector: str, expected: str) -> "Assert":
        """断言输入值相等"""
        actual = await self.page.locator(selector).input_value()
        if actual != expected:
            self._last_result = False
            self._last_error = f"值不匹配: 期望 '{expected}', 实际 '{actual}'"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def value_empty(self, selector: str) -> "Assert":
        """断言输入值为空"""
        actual = await self.page.locator(selector).input_value()
        if actual:
            self._last_result = False
            self._last_error = f"值不为空: {actual}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def value_not_empty(self, selector: str) -> "Assert":
        """断言输入值不为空"""
        actual = await self.page.locator(selector).input_value()
        if not actual:
            self._last_result = False
            self._last_error = "值为空"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    # ==================== 数量断言 ====================
    
    async def count_equals(self, selector: str, expected: int) -> "Assert":
        """断言元素数量相等"""
        actual = await self.page.locator(selector).count()
        if actual != expected:
            self._last_result = False
            self._last_error = f"数量不匹配: 期望 {expected}, 实际 {actual}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def count_greater_than(self, selector: str, expected: int) -> "Assert":
        """断言元素数量大于"""
        actual = await self.page.locator(selector).count()
        if actual <= expected:
            self._last_result = False
            self._last_error = f"数量不足: 期望 >{expected}, 实际 {actual}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def count_less_than(self, selector: str, expected: int) -> "Assert":
        """断言元素数量小于"""
        actual = await self.page.locator(selector).count()
        if actual >= expected:
            self._last_result = False
            self._last_error = f"数量过多: 期望 <{expected}, 实际 {actual}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    # ==================== 属性断言 ====================
    
    async def attribute_equals(
        self, 
        selector: str, 
        attribute: str, 
        expected: str
    ) -> "Assert":
        """断言属性值相等"""
        actual = await self.page.locator(selector).get_attribute(attribute)
        if actual != expected:
            self._last_result = False
            self._last_error = f"属性 '{attribute}' 不匹配: 期望 '{expected}', 实际 '{actual}'"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    async def attribute_exists(self, selector: str, attribute: str) -> "Assert":
        """断言属性存在"""
        value = await self.page.locator(selector).get_attribute(attribute)
        if value is None:
            self._last_result = False
            self._last_error = f"属性不存在: {attribute}"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    # ==================== CSS断言 ====================
    
    async def css_equals(
        self, 
        selector: str, 
        property: str, 
        expected: str
    ) -> "Assert":
        """断言CSS属性值"""
        actual = await self.page.locator(selector).evaluate(
            f"el => getComputedStyle(el).{property}"
        )
        if actual != expected:
            self._last_result = False
            self._last_error = f"CSS '{property}' 不匹配: 期望 '{expected}', 实际 '{actual}'"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    # ==================== 自定义断言 ====================
    
    async def custom(self, condition: callable, message: str = "") -> "Assert":
        """自定义断言"""
        import asyncio
        
        if asyncio.iscoroutinefunction(condition):
            result = await condition()
        else:
            result = condition()
        
        if not result:
            self._last_result = False
            self._last_error = message or "自定义断言失败"
            raise AssertionError(self._last_error)
        self._last_result = True
        return self
    
    # ==================== 组合断言 ====================
    
    async def all(self, *assertions) -> "Assert":
        """执行所有断言"""
        for assertion in assertions:
            if asyncio.iscoroutinefunction(assertion):
                await assertion()
            else:
                assertion()
        return self
    
    async def any(self, *assertions) -> "Assert":
        """任一断言通过即可"""
        errors = []
        for assertion in assertions:
            try:
                if asyncio.iscoroutinefunction(assertion):
                    await assertion()
                else:
                    assertion()
                return self  # 任一通过即返回
            except AssertionError as e:
                errors.append(str(e))
        
        self._last_result = False
        self._last_error = f"所有断言都失败: {errors}"
        raise AssertionError(self._last_error)


import asyncio
