"""
运行时间监控
支持可用性检测、响应时间追踪
"""
import asyncio
import json
from dataclasses import dataclass, field
from typing import Optional, List, Dict, Any, Callable, Awaitable
from datetime import datetime, timedelta
from pathlib import Path
from playwright.async_api import Page
from loguru import logger


@dataclass
class UptimeConfig:
    """运行时间监控配置"""
    check_interval: float = 60  # 检查间隔（秒）
    timeout: float = 30  # 超时时间（秒）
    expected_status: int = 200  # 预期状态码
    response_time_threshold: float = 5000  # 响应时间阈值（毫秒）
    history_size: int = 1000  # 历史记录大小
    alert_on_failure: bool = True
    alert_consecutive_failures: int = 3  # 连续失败次数告警
    on_alert: Optional[Callable[[str, Dict], Awaitable[None]]] = None


@dataclass
class CheckResult:
    """检查结果"""
    timestamp: str
    url: str
    success: bool
    status_code: Optional[int] = None
    response_time_ms: float = 0.0
    error: Optional[str] = None
    content_length: int = 0
    is_up: bool = True


@dataclass
class UptimeStats:
    """运行时间统计"""
    total_checks: int = 0
    successful_checks: int = 0
    failed_checks: int = 0
    uptime_percentage: float = 100.0
    avg_response_time_ms: float = 0.0
    min_response_time_ms: float = 0.0
    max_response_time_ms: float = 0.0
    last_check: Optional[str] = None
    last_success: Optional[str] = None
    last_failure: Optional[str] = None
    consecutive_failures: int = 0
    current_status: str = "unknown"  # up, down, unknown


@dataclass
class UptimeReport:
    """运行时间报告"""
    url: str
    stats: UptimeStats
    recent_checks: List[CheckResult]
    period_start: str
    period_end: str
    incidents: List[Dict[str, Any]] = field(default_factory=list)


class UptimeMonitor:
    """
    运行时间监控器
    监控网站可用性和响应时间
    """

    def __init__(
        self,
        page: Page,
        config: Optional[UptimeConfig] = None,
    ):
        self.page = page
        self.config = config or UptimeConfig()
        self._stats = UptimeStats()
        self._history: List[CheckResult] = []
        self._incidents: List[Dict[str, Any]] = []
        self._is_monitoring = False
        self._monitor_task: Optional[asyncio.Task] = None
        self._target_url: Optional[str] = None

    # ==================== 监控控制 ====================

    async def start(self, url: str):
        """
        开始监控

        Args:
            url: 监控目标 URL
        """
        if self._is_monitoring:
            logger.warning("监控已在运行中")
            return

        self._target_url = url
        self._is_monitoring = True
        self._monitor_task = asyncio.create_task(self._monitor_loop())

        logger.info(f"开始监控: {url}, 间隔: {self.config.check_interval}s")

    async def stop(self):
        """停止监控"""
        if not self._is_monitoring:
            return

        self._is_monitoring = False

        if self._monitor_task:
            self._monitor_task.cancel()
            try:
                await self._monitor_task
            except asyncio.CancelledError:
                pass
            self._monitor_task = None

        logger.info("监控已停止")

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.stop()

    # ==================== 检查执行 ====================

    async def check(self, url: Optional[str] = None) -> CheckResult:
        """
        执行单次检查

        Args:
            url: 检查 URL

        Returns:
            CheckResult: 检查结果
        """
        target_url = url or self._target_url
        if not target_url:
            raise ValueError("未指定监控 URL")

        start_time = datetime.now()
        result = CheckResult(
            timestamp=start_time.isoformat(),
            url=target_url,
            success=False,
        )

        try:
            # 记录请求开始时间
            request_start = asyncio.get_event_loop().time()

            # 导航到页面
            response = await self.page.goto(
                target_url,
                timeout=self.config.timeout * 1000,
                wait_until="domcontentloaded",
            )

            # 计算响应时间
            request_end = asyncio.get_event_loop().time()
            result.response_time_ms = (request_end - request_start) * 1000

            if response:
                result.status_code = response.status
                result.success = response.status == self.config.expected_status
                result.content_length = int(response.headers.get("content-length", 0))

        except asyncio.TimeoutError:
            result.error = "请求超时"
            result.is_up = False

        except Exception as e:
            result.error = str(e)
            result.is_up = False

        # 判断是否可用
        result.is_up = result.success and result.response_time_ms < self.config.response_time_threshold

        # 更新统计
        self._update_stats(result)

        # 添加到历史
        self._add_to_history(result)

        return result

    async def _monitor_loop(self):
        """监控循环"""
        while self._is_monitoring:
            try:
                result = await self.check()

                # 检查告警条件
                await self._check_alerts(result)

            except Exception as e:
                logger.error(f"监控检查失败: {e}")

            await asyncio.sleep(self.config.check_interval)

    # ==================== 统计更新 ====================

    def _update_stats(self, result: CheckResult):
        """更新统计信息"""
        self._stats.total_checks += 1
        self._stats.last_check = result.timestamp

        if result.success:
            self._stats.successful_checks += 1
            self._stats.last_success = result.timestamp
            self._stats.consecutive_failures = 0
            self._stats.current_status = "up"
        else:
            self._stats.failed_checks += 1
            self._stats.last_failure = result.timestamp
            self._stats.consecutive_failures += 1
            self._stats.current_status = "down"

            # 记录故障
            if self._stats.consecutive_failures == 1:
                self._incidents.append({
                    "type": "down",
                    "start_time": result.timestamp,
                    "error": result.error,
                })

        # 计算可用率
        self._stats.uptime_percentage = (
            self._stats.successful_checks / self._stats.total_checks * 100
        )

        # 更新响应时间统计
        if result.success:
            response_times = [
                r.response_time_ms for r in self._history[-100:]
                if r.success
            ]
            if response_times:
                self._stats.avg_response_time_ms = sum(response_times) / len(response_times)
                self._stats.min_response_time_ms = min(response_times)
                self._stats.max_response_time_ms = max(response_times)

    def _add_to_history(self, result: CheckResult):
        """添加到历史记录"""
        self._history.append(result)

        # 限制历史大小
        if len(self._history) > self.config.history_size:
            self._history.pop(0)

    # ==================== 告警处理 ====================

    async def _check_alerts(self, result: CheckResult):
        """检查告警条件"""
        if not self.config.alert_on_failure:
            return

        # 连续失败告警
        if self._stats.consecutive_failures >= self.config.alert_consecutive_failures:
            alert_data = {
                "type": "consecutive_failures",
                "url": result.url,
                "consecutive_failures": self._stats.consecutive_failures,
                "last_error": result.error,
                "timestamp": result.timestamp,
            }

            logger.warning(
                f"告警: 连续失败 {self._stats.consecutive_failures} 次 - {result.url}"
            )

            if self.config.on_alert:
                await self.config.on_alert("consecutive_failures", alert_data)

        # 响应时间告警
        if result.success and result.response_time_ms > self.config.response_time_threshold:
            alert_data = {
                "type": "slow_response",
                "url": result.url,
                "response_time_ms": result.response_time_ms,
                "threshold_ms": self.config.response_time_threshold,
                "timestamp": result.timestamp,
            }

            logger.warning(
                f"告警: 响应时间过长 {result.response_time_ms:.0f}ms - {result.url}"
            )

            if self.config.on_alert:
                await self.config.on_alert("slow_response", alert_data)

    # ==================== 报告生成 ====================

    def get_report(self, hours: int = 24) -> UptimeReport:
        """
        生成报告

        Args:
            hours: 报告时间范围（小时）

        Returns:
            UptimeReport: 报告
        """
        now = datetime.now()
        start_time = now - timedelta(hours=hours)

        # 过滤历史记录
        recent_checks = [
            r for r in self._history
            if datetime.fromisoformat(r.timestamp) >= start_time
        ]

        # 计算时间范围内的统计
        period_stats = UptimeStats()
        for check in recent_checks:
            period_stats.total_checks += 1
            if check.success:
                period_stats.successful_checks += 1

        if period_stats.total_checks > 0:
            period_stats.uptime_percentage = (
                period_stats.successful_checks / period_stats.total_checks * 100
            )

        # 获取时间范围内的事件
        incidents = [
            i for i in self._incidents
            if datetime.fromisoformat(i["start_time"]) >= start_time
        ]

        return UptimeReport(
            url=self._target_url or "unknown",
            stats=self._stats,
            recent_checks=recent_checks[-100:],  # 最近 100 次
            period_start=start_time.isoformat(),
            period_end=now.isoformat(),
            incidents=incidents,
        )

    async def export_report(self, file_path: str, hours: int = 24):
        """导出报告"""
        report = self.get_report(hours)

        data = {
            "url": report.url,
            "period": {
                "start": report.period_start,
                "end": report.period_end,
            },
            "stats": {
                "total_checks": report.stats.total_checks,
                "successful_checks": report.stats.successful_checks,
                "failed_checks": report.stats.failed_checks,
                "uptime_percentage": report.stats.uptime_percentage,
                "avg_response_time_ms": report.stats.avg_response_time_ms,
                "current_status": report.stats.current_status,
            },
            "recent_checks": [
                {
                    "timestamp": c.timestamp,
                    "success": c.success,
                    "response_time_ms": c.response_time_ms,
                    "error": c.error,
                }
                for c in report.recent_checks
            ],
            "incidents": report.incidents,
        }

        Path(file_path).parent.mkdir(parents=True, exist_ok=True)
        with open(file_path, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)

        logger.info(f"报告已导出: {file_path}")

    # ==================== 状态查询 ====================

    def get_stats(self) -> UptimeStats:
        """获取统计信息"""
        return self._stats

    def is_up(self) -> bool:
        """是否可用"""
        return self._stats.current_status == "up"

    def get_history(self, limit: int = 100) -> List[CheckResult]:
        """获取历史记录"""
        return self._history[-limit:]

    def get_current_status(self) -> Dict[str, Any]:
        """获取当前状态"""
        return {
            "url": self._target_url,
            "status": self._stats.current_status,
            "uptime_percentage": self._stats.uptime_percentage,
            "last_check": self._stats.last_check,
            "consecutive_failures": self._stats.consecutive_failures,
            "avg_response_time_ms": self._stats.avg_response_time_ms,
        }


def create_uptime_monitor(
    page: Page,
    config: Optional[UptimeConfig] = None,
) -> UptimeMonitor:
    """创建运行时间监控器实例"""
    return UptimeMonitor(page, config)
