"""
Event Reporter — 将 Frida Hook 事件上报到 SDK 服务端

职责：
- 接收 FridaManager 回调的 hook_event
- 格式化为 SDK 服务端 WebSocket 协议
- 通过 Agent 的 WebSocket 连接上报
- 本地缓存（服务端离线时暂存）
"""

import time
import logging
import threading
from typing import Dict, Any, Optional, Callable, List
from collections import deque

logger = logging.getLogger(__name__)

MAX_BUFFER_SIZE = 500


class EventReporter:
    """Hook 事件上报器"""

    def __init__(
        self,
        send_fn: Optional[Callable[[Dict[str, Any]], None]] = None,
        buffer_size: int = MAX_BUFFER_SIZE,
    ):
        self._send_fn = send_fn
        self._buffer: deque = deque(maxlen=buffer_size)
        self._stats = {"total": 0, "sent": 0, "buffered": 0, "errors": 0}
        self._lock = threading.Lock()

    def set_send_fn(self, fn: Callable[[Dict[str, Any]], None]):
        self._send_fn = fn
        self._flush_buffer()

    def on_hook_event(self, payload: Dict[str, Any]):
        event = {
            "type": "hook_event",
            "event_type": payload.get("event_type", "unknown"),
            "platform": payload.get("platform", "wechat"),
            "payload": payload.get("payload", {}),
            "timestamp": payload.get("timestamp") or time.strftime("%Y-%m-%dT%H:%M:%S"),
        }

        with self._lock:
            self._stats["total"] += 1

        if self._send_fn:
            try:
                self._send_fn(event)
                with self._lock:
                    self._stats["sent"] += 1
            except Exception as e:
                logger.warning(f"事件上报失败，暂存: {e}")
                self._buffer.append(event)
                with self._lock:
                    self._stats["buffered"] += 1
                    self._stats["errors"] += 1
        else:
            self._buffer.append(event)
            with self._lock:
                self._stats["buffered"] += 1

    def _flush_buffer(self):
        if not self._send_fn:
            return
        while self._buffer:
            event = self._buffer.popleft()
            try:
                self._send_fn(event)
                with self._lock:
                    self._stats["sent"] += 1
                    self._stats["buffered"] = max(0, self._stats["buffered"] - 1)
            except Exception:
                self._buffer.appendleft(event)
                break

    def get_stats(self) -> Dict[str, Any]:
        with self._lock:
            return dict(self._stats)

    def get_buffered_events(self, limit: int = 50) -> List[Dict[str, Any]]:
        return list(self._buffer)[:limit]
