"""
网络拦截和监控模块
"""
import json
from typing import Optional, Callable, Dict, Any, List
from dataclasses import dataclass, field
from playwright.async_api import Page, Request, Response, Route
from loguru import logger
from datetime import datetime
import re


@dataclass
class RequestLog:
    """请求日志"""
    url: str
    method: str
    status: Optional[int] = None
    request_time: datetime = field(default_factory=datetime.now)
    response_time: Optional[datetime] = None
    request_headers: Dict[str, str] = field(default_factory=dict)
    response_headers: Dict[str, str] = field(default_factory=dict)
    request_body: Optional[str] = None
    response_body: Optional[str] = None
    duration_ms: Optional[float] = None
    error: Optional[str] = None


class NetworkMonitor:
    """
    网络监控器
    记录所有网络请求和响应
    """
    
    def __init__(self, page: Page):
        self.page = page
        self.requests: List[RequestLog] = []
        self._request_map: Dict[str, RequestLog] = {}
    
    def start(self):
        """开始监控"""
        self.page.on("request", self._on_request)
        self.page.on("response", self._on_response)
        self.page.on("requestfailed", self._on_request_failed)
        logger.info("网络监控已启动")
    
    def stop(self):
        """停止监控"""
        self.page.remove_listener("request", self._on_request)
        self.page.remove_listener("response", self._on_response)
        self.page.remove_listener("requestfailed", self._on_request_failed)
        logger.info("网络监控已停止")
    
    def _on_request(self, request: Request):
        """请求事件处理"""
        log = RequestLog(
            url=request.url,
            method=request.method,
            request_headers=dict(request.headers),
            request_body=request.post_data,
        )
        self._request_map[request.url] = log
        self.requests.append(log)
    
    async def _on_response(self, response: Response):
        """响应事件处理"""
        request = response.request
        if request.url in self._request_map:
            log = self._request_map[request.url]
            log.status = response.status
            log.response_time = datetime.now()
            log.response_headers = dict(response.headers)
            log.duration_ms = (log.response_time - log.request_time).total_seconds() * 1000

            # 尝试获取响应体
            try:
                if response.status < 400:
                    body = await response.text()
                    log.response_body = body[:10000]  # 限制大小
            except:
                pass
    
    def _on_request_failed(self, request: Request):
        """请求失败事件处理"""
        if request.url in self._request_map:
            log = self._request_map[request.url]
            log.error = request.failure
            log.response_time = datetime.now()
            log.duration_ms = (log.response_time - log.request_time).total_seconds() * 1000
    
    def get_requests(self, url_pattern: Optional[str] = None) -> List[RequestLog]:
        """
        获取请求日志
        
        Args:
            url_pattern: URL正则模式
            
        Returns:
            List[RequestLog]: 请求日志列表
        """
        if url_pattern:
            pattern = re.compile(url_pattern)
            return [r for r in self.requests if pattern.search(r.url)]
        return self.requests
    
    def get_api_calls(self) -> List[RequestLog]:
        """获取API调用（JSON请求）"""
        return [
            r for r in self.requests
            if "application/json" in r.request_headers.get("accept", "")
            or "application/json" in r.response_headers.get("content-type", "")
            or "/api/" in r.url
        ]
    
    def get_failed_requests(self) -> List[RequestLog]:
        """获取失败的请求"""
        return [r for r in self.requests if r.error or (r.status and r.status >= 400)]
    
    def get_slow_requests(self, threshold_ms: float = 1000) -> List[RequestLog]:
        """
        获取慢请求
        
        Args:
            threshold_ms: 阈值（毫秒）
        """
        return [
            r for r in self.requests
            if r.duration_ms and r.duration_ms > threshold_ms
        ]
    
    def clear(self):
        """清空日志"""
        self.requests.clear()
        self._request_map.clear()
    
    def summary(self) -> Dict[str, Any]:
        """生成摘要"""
        total = len(self.requests)
        failed = len(self.get_failed_requests())
        api_calls = len(self.get_api_calls())
        slow = len(self.get_slow_requests())
        
        avg_duration = 0
        if self.requests:
            durations = [r.duration_ms for r in self.requests if r.duration_ms]
            if durations:
                avg_duration = sum(durations) / len(durations)
        
        return {
            "total_requests": total,
            "failed_requests": failed,
            "api_calls": api_calls,
            "slow_requests": slow,
            "avg_duration_ms": round(avg_duration, 2),
        }
    
    def print_summary(self):
        """打印摘要"""
        s = self.summary()
        print(f"\n=== 网络监控摘要 ===")
        print(f"总请求数: {s['total_requests']}")
        print(f"失败请求: {s['failed_requests']}")
        print(f"API调用: {s['api_calls']}")
        print(f"慢请求(>1s): {s['slow_requests']}")
        print(f"平均耗时: {s['avg_duration_ms']}ms")


class NetworkInterceptor:
    """
    网络拦截器
    拦截、修改、阻止网络请求
    """
    
    def __init__(self, page: Page):
        self.page = page
        self._routes: List[Dict[str, Any]] = []
    
    async def block(self, url_pattern: str):
        """
        阻止匹配的请求
        
        Args:
            url_pattern: URL正则模式
        """
        async def handler(route: Route):
            logger.debug(f"阻止请求: {route.request.url}")
            await route.abort()
        
        await self.page.route(url_pattern, handler)
        self._routes.append({"pattern": url_pattern, "action": "block"})
        logger.info(f"已设置拦截规则(阻止): {url_pattern}")
    
    async def mock(
        self, 
        url_pattern: str, 
        response_body: Any,
        status: int = 200,
        headers: Optional[Dict[str, str]] = None,
    ):
        """
        模拟响应
        
        Args:
            url_pattern: URL正则模式
            response_body: 响应体
            status: 状态码
            headers: 响应头
        """
        async def handler(route: Route):
            body = json.dumps(response_body) if isinstance(response_body, (dict, list)) else str(response_body)
            default_headers = {"content-type": "application/json"}
            default_headers.update(headers or {})
            
            logger.debug(f"模拟响应: {route.request.url}")
            await route.fulfill(status=status, body=body, headers=default_headers)
        
        await self.page.route(url_pattern, handler)
        self._routes.append({"pattern": url_pattern, "action": "mock"})
        logger.info(f"已设置拦截规则(模拟): {url_pattern}")
    
    async def modify(
        self,
        url_pattern: str,
        request_modifier: Optional[Callable[[Request], Dict[str, Any]]] = None,
        response_modifier: Optional[Callable[[Response, str], str]] = None,
    ):
        """
        修改请求/响应
        
        Args:
            url_pattern: URL正则模式
            request_modifier: 请求修改函数
            response_modifier: 响应修改函数
        """
        async def handler(route: Route):
            request = route.request
            
            if request_modifier:
                modifications = request_modifier(request)
                await route.continue_(**modifications)
            elif response_modifier:
                response = await route.fetch()
                body = await response.text()
                modified_body = response_modifier(response, body)
                await route.fulfill(response=response, body=modified_body)
            else:
                await route.continue_()
        
        await self.page.route(url_pattern, handler)
        self._routes.append({"pattern": url_pattern, "action": "modify"})
        logger.info(f"已设置拦截规则(修改): {url_pattern}")
    
    async def redirect(self, url_pattern: str, target_url: str):
        """
        重定向请求
        
        Args:
            url_pattern: URL正则模式
            target_url: 目标URL
        """
        async def handler(route: Route):
            logger.debug(f"重定向: {route.request.url} -> {target_url}")
            await route.redirect(target_url)
        
        await self.page.route(url_pattern, handler)
        self._routes.append({"pattern": url_pattern, "action": "redirect", "target": target_url})
        logger.info(f"已设置拦截规则(重定向): {url_pattern} -> {target_url}")
    
    async def clear_all(self):
        """清除所有拦截规则"""
        for route_info in self._routes:
            await self.page.unroute(route_info["pattern"])
        self._routes.clear()
        logger.info("已清除所有拦截规则")
    
    def list_routes(self) -> List[Dict[str, Any]]:
        """列出所有拦截规则"""
        return self._routes.copy()


class BlockResources:
    """
    资源阻止器
    阻止特定类型的资源加载，加速页面加载
    """
    
    RESOURCE_TYPES = {
        "image": ["image", "images"],
        "stylesheet": ["stylesheet", "css"],
        "font": ["font"],
        "media": ["media"],
        "script": ["script", "javascript"],
        "websocket": ["websocket"],
        "other": ["other"],
    }
    
    def __init__(self, page: Page):
        self.page = page
        self._blocked_types: List[str] = []
    
    async def block_images(self):
        """阻止图片"""
        await self._block_resource_type("image")
    
    async def block_styles(self):
        """阻止样式表"""
        await self._block_resource_type("stylesheet")
    
    async def block_fonts(self):
        """阻止字体"""
        await self._block_resource_type("font")
    
    async def block_media(self):
        """阻止媒体"""
        await self._block_resource_type("media")
    
    async def block_scripts(self):
        """阻止脚本"""
        await self._block_resource_type("script")
    
    async def block_all_except_html(self):
        """只加载HTML，阻止其他所有资源"""
        async def handler(route: Route):
            if route.request.resource_type == "document":
                await route.continue_()
            else:
                await route.abort()
        
        await self.page.route("**/*", handler)
        logger.info("已阻止除HTML外的所有资源")
    
    async def _block_resource_type(self, resource_type: str):
        """阻止特定资源类型"""
        async def handler(route: Route):
            if route.request.resource_type == resource_type:
                await route.abort()
            else:
                await route.continue_()
        
        await self.page.route("**/*", handler)
        self._blocked_types.append(resource_type)
        logger.info(f"已阻止资源类型: {resource_type}")
