"""
日志和追踪模块
提供详细的日志记录和追踪功能
"""
import json
from typing import Optional, List, Dict, Any
from pathlib import Path
from datetime import datetime
from loguru import logger
from dataclasses import dataclass, field


@dataclass
class TraceEvent:
    """追踪事件"""
    name: str
    category: str
    timestamp: datetime
    duration_ms: Optional[float] = None
    data: Dict[str, Any] = field(default_factory=dict)


class TraceCollector:
    """
    追踪收集器
    收集和分析操作追踪
    """
    
    def __init__(self, output_dir: str = "./traces"):
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(parents=True, exist_ok=True)
        self._events: List[TraceEvent] = []
        self._current_trace: Optional[str] = None
    
    def start_trace(self, name: str):
        """开始追踪"""
        self._current_trace = name
        self._events.clear()
        
        event = TraceEvent(
            name=f"trace_start",
            category="trace",
            timestamp=datetime.now(),
            data={"trace_name": name},
        )
        self._events.append(event)
        
        logger.info(f"开始追踪: {name}")
    
    def end_trace(self) -> List[TraceEvent]:
        """结束追踪"""
        event = TraceEvent(
            name="trace_end",
            category="trace",
            timestamp=datetime.now(),
        )
        self._events.append(event)
        
        logger.info(f"结束追踪: {self._current_trace}")
        
        events = self._events.copy()
        self._current_trace = None
        
        return events
    
    def record_event(
        self,
        name: str,
        category: str = "action",
        duration_ms: float = None,
        **kwargs,
    ):
        """记录事件"""
        event = TraceEvent(
            name=name,
            category=category,
            timestamp=datetime.now(),
            duration_ms=duration_ms,
            data=kwargs,
        )
        self._events.append(event)
    
    def record_action(self, action: str, selector: str = None, **kwargs):
        """记录操作"""
        self.record_event(
            name=action,
            category="action",
            selector=selector,
            **kwargs,
        )
    
    def record_navigation(self, url: str, duration_ms: float = None):
        """记录导航"""
        self.record_event(
            name="navigate",
            category="navigation",
            duration_ms=duration_ms,
            url=url,
        )
    
    def record_wait(self, condition: str, duration_ms: float):
        """记录等待"""
        self.record_event(
            name="wait",
            category="wait",
            duration_ms=duration_ms,
            condition=condition,
        )
    
    def get_events(self, category: str = None) -> List[TraceEvent]:
        """获取事件"""
        if category:
            return [e for e in self._events if e.category == category]
        return self._events.copy()
    
    def get_summary(self) -> Dict[str, Any]:
        """获取摘要"""
        categories = {}
        total_duration = 0
        
        for event in self._events:
            if event.category not in categories:
                categories[event.category] = {"count": 0, "total_duration": 0}
            
            categories[event.category]["count"] += 1
            
            if event.duration_ms:
                categories[event.category]["total_duration"] += event.duration_ms
                total_duration += event.duration_ms
        
        return {
            "total_events": len(self._events),
            "total_duration_ms": total_duration,
            "categories": categories,
        }
    
    def export_chrome_trace(self, filepath: str = None):
        """导出Chrome Tracing格式"""
        events = []
        
        for event in self._events:
            ts = int(event.timestamp.timestamp() * 1000000)  # 微秒
            
            trace_event = {
                "name": event.name,
                "cat": event.category,
                "ph": "i" if event.duration_ms is None else "X",
                "ts": ts,
                "pid": 1,
                "tid": 1,
                "args": event.data,
            }
            
            if event.duration_ms:
                trace_event["dur"] = int(event.duration_ms * 1000)  # 微秒
            
            events.append(trace_event)
        
        filepath = filepath or str(self.output_dir / f"trace_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json")
        
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(events, f, ensure_ascii=False)
        
        logger.info(f"追踪已导出: {filepath}")
        return filepath


class ActionLogger:
    """
    操作日志记录器
    详细记录所有浏览器操作
    """
    
    def __init__(self, log_file: str = None):
        self.log_file = Path(log_file) if log_file else None
        self._logs: List[Dict[str, Any]] = []
    
    def log(
        self,
        action: str,
        selector: str = None,
        value: Any = None,
        success: bool = True,
        error: str = None,
    ):
        """记录操作"""
        entry = {
            "timestamp": datetime.now().isoformat(),
            "action": action,
            "selector": selector,
            "value": str(value)[:100] if value else None,
            "success": success,
            "error": error,
        }
        
        self._logs.append(entry)
        
        if self.log_file:
            with open(self.log_file, 'a', encoding='utf-8') as f:
                f.write(json.dumps(entry, ensure_ascii=False) + '\n')
    
    def get_logs(self, action: str = None) -> List[Dict]:
        """获取日志"""
        if action:
            return [l for l in self._logs if l["action"] == action]
        return self._logs.copy()
    
    def get_failed_actions(self) -> List[Dict]:
        """获取失败的操作"""
        return [l for l in self._logs if not l["success"]]
    
    def clear(self):
        """清除日志"""
        self._logs.clear()


class PerformanceLogger:
    """
    性能日志记录器
    记录性能相关数据
    """
    
    def __init__(self):
        self._metrics: Dict[str, List[float]] = {}
    
    def record(self, metric_name: str, value: float):
        """记录指标"""
        if metric_name not in self._metrics:
            self._metrics[metric_name] = []
        self._metrics[metric_name].append(value)
    
    def get_stats(self, metric_name: str) -> Dict[str, float]:
        """获取统计"""
        if metric_name not in self._metrics:
            return {}
        
        values = self._metrics[metric_name]
        
        return {
            "count": len(values),
            "avg": sum(values) / len(values),
            "min": min(values),
            "max": max(values),
            "sum": sum(values),
        }
    
    def get_all_stats(self) -> Dict[str, Dict[str, float]]:
        """获取所有统计"""
        return {name: self.get_stats(name) for name in self._metrics}


class ErrorTracker:
    """
    错误追踪器
    追踪和分析错误
    """
    
    def __init__(self):
        self._errors: List[Dict[str, Any]] = []
    
    def track(
        self,
        error: Exception,
        context: Dict[str, Any] = None,
        screenshot: str = None,
    ):
        """追踪错误"""
        import traceback
        
        entry = {
            "timestamp": datetime.now().isoformat(),
            "error_type": type(error).__name__,
            "error_message": str(error),
            "traceback": traceback.format_exc(),
            "context": context or {},
            "screenshot": screenshot,
        }
        
        self._errors.append(entry)
        logger.error(f"错误追踪: {entry['error_type']}: {entry['error_message']}")
    
    def get_errors(self, error_type: str = None) -> List[Dict]:
        """获取错误"""
        if error_type:
            return [e for e in self._errors if e["error_type"] == error_type]
        return self._errors.copy()
    
    def get_error_summary(self) -> Dict[str, int]:
        """获取错误摘要"""
        summary = {}
        for error in self._errors:
            error_type = error["error_type"]
            summary[error_type] = summary.get(error_type, 0) + 1
        return summary
    
    def has_errors(self) -> bool:
        """是否有错误"""
        return len(self._errors) > 0
    
    def clear(self):
        """清除错误"""
        self._errors.clear()


class StepReporter:
    """
    步骤报告器
    生成测试步骤报告
    """
    
    def __init__(self):
        self._steps: List[Dict[str, Any]] = []
        self._current_step: Optional[int] = None
    
    def start_step(self, name: str, description: str = None):
        """开始步骤"""
        step = {
            "name": name,
            "description": description,
            "start_time": datetime.now(),
            "end_time": None,
            "status": "running",
            "error": None,
        }
        
        self._steps.append(step)
        self._current_step = len(self._steps) - 1
        
        logger.info(f"开始步骤: {name}")
    
    def end_step(self, success: bool = True, error: str = None):
        """结束步骤"""
        if self._current_step is not None:
            step = self._steps[self._current_step]
            step["end_time"] = datetime.now()
            step["status"] = "passed" if success else "failed"
            step["error"] = error
            
            duration = (step["end_time"] - step["start_time"]).total_seconds()
            
            status_emoji = "✅" if success else "❌"
            logger.info(f"{status_emoji} 结束步骤: {step['name']} ({duration:.2f}s)")
            
            self._current_step = None
    
    def get_report(self) -> Dict[str, Any]:
        """获取报告"""
        total = len(self._steps)
        passed = sum(1 for s in self._steps if s["status"] == "passed")
        failed = total - passed
        
        steps_data = []
        for step in self._steps:
            duration = 0
            if step["end_time"] and step["start_time"]:
                duration = (step["end_time"] - step["start_time"]).total_seconds()
            
            steps_data.append({
                "name": step["name"],
                "description": step["description"],
                "status": step["status"],
                "duration_seconds": duration,
                "error": step["error"],
            })
        
        return {
            "total_steps": total,
            "passed": passed,
            "failed": failed,
            "steps": steps_data,
        }
    
    def export_html(self, filepath: str):
        """导出HTML报告"""
        report = self.get_report()
        
        html = f"""
<!DOCTYPE html>
<html>
<head>
    <title>Step Report</title>
    <style>
        body {{ font-family: Arial, sans-serif; padding: 20px; }}
        .summary {{ background: #f5f5f5; padding: 20px; margin-bottom: 20px; }}
        .step {{ padding: 15px; margin-bottom: 10px; border-radius: 5px; }}
        .step.passed {{ background: #e8f5e9; border-left: 4px solid #4CAF50; }}
        .step.failed {{ background: #ffebee; border-left: 4px solid #f44336; }}
        .step-name {{ font-weight: bold; margin-bottom: 5px; }}
        .step-duration {{ color: #666; font-size: 14px; }}
    </style>
</head>
<body>
    <h1>Step Report</h1>
    <div class="summary">
        <p>Total: {report['total_steps']}</p>
        <p>Passed: {report['passed']}</p>
        <p>Failed: {report['failed']}</p>
    </div>
    <div class="steps">
"""
        
        for step in report["steps"]:
            html += f"""
        <div class="step {step['status']}">
            <div class="step-name">{step['name']}</div>
            <div class="step-duration">{step['duration_seconds']:.2f}s</div>
            {f'<div class="error">{step["error"]}</div>' if step['error'] else ''}
        </div>
"""
        
        html += """
    </div>
</body>
</html>
"""
        
        Path(filepath).parent.mkdir(parents=True, exist_ok=True)
        Path(filepath).write_text(html, encoding='utf-8')
        
        logger.info(f"步骤报告已导出: {filepath}")