"""
验证器和检查器
提供各种验证功能
"""
import re
from typing import Optional, List, Dict, Any
from playwright.async_api import Page
from loguru import logger


class PageValidator:
    """
    页面验证器
    验证页面状态和内容
    """
    
    def __init__(self, page: Page):
        self.page = page
    
    async def validate_url(self, expected: str, exact: bool = True) -> bool:
        """验证URL"""
        actual = self.page.url
        if exact:
            result = actual == expected
        else:
            result = expected in actual
        
        if result:
            logger.debug(f"URL验证通过: {actual}")
        else:
            logger.error(f"URL验证失败: 期望 '{expected}', 实际 '{actual}'")
        
        return result
    
    async def validate_title(self, expected: str, contains: bool = True) -> bool:
        """验证标题"""
        actual = await self.page.title()
        
        if contains:
            result = expected in actual
        else:
            result = actual == expected
        
        if result:
            logger.debug(f"标题验证通过: {actual}")
        else:
            logger.error(f"标题验证失败: 期望 '{expected}', 实际 '{actual}'")
        
        return result
    
    async def validate_element_exists(self, selector: str) -> bool:
        """验证元素存在"""
        count = await self.page.locator(selector).count()
        result = count > 0
        
        if result:
            logger.debug(f"元素存在验证通过: {selector}")
        else:
            logger.error(f"元素不存在: {selector}")
        
        return result
    
    async def validate_element_visible(self, selector: str) -> bool:
        """验证元素可见"""
        try:
            visible = await self.page.locator(selector).is_visible()
            if visible:
                logger.debug(f"元素可见验证通过: {selector}")
            else:
                logger.error(f"元素不可见: {selector}")
            return visible
        except:
            logger.error(f"元素不存在或不可见: {selector}")
            return False
    
    async def validate_text_present(self, text: str) -> bool:
        """验证文本存在"""
        try:
            element = self.page.get_by_text(text)
            count = await element.count()
            result = count > 0
            
            if result:
                logger.debug(f"文本存在验证通过: {text[:50]}")
            else:
                logger.error(f"文本不存在: {text[:50]}")
            
            return result
        except:
            return False
    
    async def validate_text_in_element(self, selector: str, text: str) -> bool:
        """验证元素包含文本"""
        try:
            element_text = await self.page.locator(selector).text_content()
            result = text in (element_text or "")
            
            if result:
                logger.debug(f"元素文本验证通过: {selector}")
            else:
                logger.error(f"元素文本验证失败: {selector}")
            
            return result
        except:
            return False
    
    async def validate_image_loaded(self, selector: str) -> bool:
        """验证图片已加载"""
        try:
            complete = await self.page.locator(selector).evaluate(
                "el => el.complete && el.naturalHeight > 0"
            )
            
            if complete:
                logger.debug(f"图片加载验证通过: {selector}")
            else:
                logger.error(f"图片未加载: {selector}")
            
            return complete
        except:
            return False
    
    async def validate_link_working(self, selector: str) -> bool:
        """验证链接有效"""
        try:
            href = await self.page.locator(selector).get_attribute("href")
            if not href:
                logger.error(f"链接没有href: {selector}")
                return False
            
            # 检查链接格式
            if href.startswith("http"):
                logger.debug(f"链接格式有效: {href}")
                return True
            elif href.startswith("/") or href.startswith("#"):
                logger.debug(f"相对链接有效: {href}")
                return True
            
            return False
        except:
            return False
    
    async def validate_form_valid(self, form_selector: str = "form") -> Dict[str, Any]:
        """验证表单有效性"""
        result = {
            "valid": True,
            "errors": [],
        }
        
        try:
            # 检查必填字段
            required_fields = await self.page.locator(f"{form_selector} [required]").all()
            
            for field in required_fields:
                value = await field.input_value() if await field.evaluate("el => el.tagName") in ["INPUT", "TEXTAREA"] else ""
                
                if not value:
                    name = await field.get_attribute("name") or await field.get_attribute("id")
                    result["errors"].append(f"必填字段为空: {name}")
                    result["valid"] = False
            
            # 检查email格式
            email_fields = await self.page.locator(f"{form_selector} input[type='email']").all()
            email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
            
            for field in email_fields:
                value = await field.input_value()
                if value and not re.match(email_pattern, value):
                    result["errors"].append(f"Email格式无效: {value}")
                    result["valid"] = False
            
        except Exception as e:
            result["valid"] = False
            result["errors"].append(str(e))
        
        return result
    
    async def validate_no_console_errors(self) -> List[str]:
        """验证没有控制台错误"""
        errors = []
        
        def handle_console(msg):
            if msg.type == "error":
                errors.append(msg.text)
        
        self.page.on("console", handle_console)
        
        # 等待一段时间收集错误
        import asyncio
        await asyncio.sleep(1)
        
        if errors:
            logger.error(f"发现控制台错误: {errors}")
        else:
            logger.debug("没有控制台错误")
        
        return errors
    
    async def validate_page_performance(self, thresholds: Dict[str, float] = None) -> Dict[str, Any]:
        """验证页面性能"""
        thresholds = thresholds or {
            "load_time": 3000,  # 3秒
            "dom_content_loaded": 2000,
        }
        
        metrics = await self.page.evaluate("""
            () => ({
                load_time: performance.timing.loadEventEnd - performance.timing.navigationStart,
                dom_content_loaded: performance.timing.domContentLoadedEventEnd - performance.timing.navigationStart,
            })
        """)
        
        result = {
            "passed": True,
            "metrics": metrics,
            "violations": [],
        }
        
        for key, threshold in thresholds.items():
            if metrics.get(key, 0) > threshold:
                result["violations"].append(f"{key}: {metrics[key]}ms > {threshold}ms")
                result["passed"] = False
        
        return result


class ContentChecker:
    """
    内容检查器
    检查页面内容
    """
    
    def __init__(self, page: Page):
        self.page = page
    
    async def check_spelling(self, selector: str = "body") -> List[str]:
        """检查拼写（简单实现）"""
        text = await self.page.locator(selector).text_content()
        
        # 常见拼写错误（示例）
        common_errors = {
            "teh": "the",
            "recieve": "receive",
            "occured": "occurred",
        }
        
        errors = []
        text_lower = text.lower()
        
        for wrong, correct in common_errors.items():
            if wrong in text_lower:
                errors.append(f"'{wrong}' 应该是 '{correct}'")
        
        return errors
    
    async def check_broken_links(self) -> List[Dict[str, str]]:
        """检查断链"""
        links = await self.page.locator("a[href]").all()
        broken = []
        
        for link in links[:20]:  # 限制检查数量
            try:
                href = await link.get_attribute("href")
                text = await link.text_content()
                
                if href and href.startswith("http"):
                    # 这里可以实际请求检查，但简化处理
                    pass
                    
            except Exception as e:
                broken.append({
                    "href": href,
                    "text": text,
                    "error": str(e),
                })
        
        return broken
    
    async def check_missing_alt_text(self) -> List[str]:
        """检查缺少alt的图片"""
        images = await self.page.locator("img:not([alt])").all()
        return [await img.get_attribute("src") or "unknown" for img in images]
    
    async def check_empty_links(self) -> List[str]:
        """检查空链接"""
        links = await self.page.locator("a[href=''], a:not([href])").all()
        return [await link.text_content() or "empty" for link in links]
    
    async def check_duplicate_ids(self) -> List[str]:
        """检查重复ID"""
        ids = await self.page.evaluate("""
            () => {
                const ids = {};
                const duplicates = [];
                document.querySelectorAll('[id]').forEach(el => {
                    if (ids[el.id]) {
                        duplicates.push(el.id);
                    } else {
                        ids[el.id] = true;
                    }
                });
                return duplicates;
            }
        """)
        
        return ids


class SecurityChecker:
    """
    安全检查器
    检查页面安全性
    """
    
    def __init__(self, page: Page):
        self.page = page
    
    async def check_https(self) -> bool:
        """检查HTTPS"""
        url = self.page.url
        result = url.startswith("https://")
        
        if result:
            logger.debug("使用HTTPS")
        else:
            logger.warning("未使用HTTPS")
        
        return result
    
    async def check_mixed_content(self) -> List[str]:
        """检查混合内容"""
        mixed = await self.page.evaluate("""
            () => {
                const issues = [];
                
                // HTTP资源在HTTPS页面
                if (location.protocol === 'https:') {
                    document.querySelectorAll('img[src^="http:"], script[src^="http:"], link[href^="http:"]').forEach(el => {
                        issues.push(el.src || el.href);
                    });
                }
                
                return issues;
            }
        """)
        
        return mixed
    
    async def check_xss_vulnerabilities(self) -> List[str]:
        """检查XSS漏洞（基本）"""
        vulnerabilities = []
        
        # 检查是否有直接innerHTML赋值
        # 这只是基本检查，不是完整的XSS扫描
        
        return vulnerabilities
    
    async def check_cookies_secure(self) -> List[Dict[str, Any]]:
        """检查Cookie安全性"""
        cookies = await self.page.context.cookies()
        insecure = []
        
        for cookie in cookies:
            issues = []
            
            if not cookie.get("secure"):
                issues.append("未设置Secure标志")
            
            if not cookie.get("httpOnly"):
                issues.append("未设置HttpOnly标志")
            
            if issues:
                insecure.append({
                    "name": cookie.get("name"),
                    "issues": issues,
                })
        
        return insecure
