#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
响应异常告警中间件模块
拦截非正常响应并推送异常日志到主系统
"""

import json
import logging
from typing import Any, Dict
from fastapi import Request, Response
from starlette.types import Message

from utils.logger import get_logger
from utils.alert_sync import get_alert_sync_service

# 设置日志
logger = get_logger("middleware.response_alert")

class ResponseAlertMiddleware:
    """
    响应异常告警中间件
    监控所有API响应，当出现非正常响应时推送告警
    """
    
    def __init__(self, app):
        self.app = app
        self.alert_service = get_alert_sync_service()
    
    async def __call__(self, scope, receive, send):
        if scope["type"] != "http":
            await self.app(scope, receive, send)
            return
        
        # 创建请求对象获取路径信息
        request = Request(scope, receive)
        
        # 捕获响应数据
        response_body = bytearray()
        
        async def send_wrapper(message: Message):
            if message["type"] == "http.response.body":
                body = message.get("body", b"")
                response_body.extend(body)
            await send(message)
        
        # 处理请求
        await self.app(scope, receive, send_wrapper)
        
        # 检查响应并发送告警
        await self._check_and_alert(request, response_body)
    
    async def _check_and_alert(self, request: Request, response_body: bytearray):
        """
        检查响应并发送告警
        
        Args:
            request: 请求对象
            response_body: 响应体
        """
        try:
            # 解析响应体，使用错误处理避免解码异常
            try:
                body_str = response_body.decode('utf-8')
            except UnicodeDecodeError:
                # 如果UTF-8解码失败，尝试使用errors='ignore'或'replace'
                try:
                    body_str = response_body.decode('utf-8', errors='replace')
                except Exception:
                    # 如果仍然失败，跳过此响应的检查
                    return
            
            if not body_str:
                return
            
            # 尝试解析JSON响应
            try:
                response_data = json.loads(body_str)
            except json.JSONDecodeError:
                # 非JSON响应，跳过检查
                return
            
            # 检查是否为标准格式响应
            if not isinstance(response_data, dict) or 'code' not in response_data:
                return
            
            response_code = response_data.get('code')
            message = response_data.get('message', '未知错误')
            
            # 只处理非成功响应 (code != 200)
            if response_code == 200:
                return
            
            # 构造告警信息
            alert_message = self._format_alert_message(request, response_code, message, response_data)
            
            # 创建日志记录用于告警推送
            log_record = self._create_log_record(alert_message, response_code)
            
            # 推送告警
            success = self.alert_service.sync_alert(log_record)
            if success:
                logger.debug(f"异常响应告警已推送: {request.method} {request.url.path} - {response_code}")
            else:
                logger.warning(f"异常响应告警推送失败: {request.method} {request.url.path} - {response_code}")
                
        except Exception as e:
            # 避免告警中间件本身的错误影响正常流程
            logger.error(f"响应告警中间件处理错误: {str(e)}")
    
    def _format_alert_message(self, request: Request, code: int, message: str, response_data: Dict[str, Any]) -> str:
        """
        格式化告警消息
        
        Args:
            request: 请求对象
            code: 响应码
            message: 响应消息
            response_data: 完整响应数据
            
        Returns:
            格式化的告警消息
        """
        method = request.method
        path = request.url.path
        client_ip = request.client.host if request.client else "unknown"
        
        # 构建基本告警信息
        alert_msg = f"API异常响应: {method} {path} 返回错误码 {code}"
        alert_msg += f" | 错误信息: {message}"
        alert_msg += f" | 客户端IP: {client_ip}"
        
        # 添加查询参数（如果有）
        if request.query_params:
            alert_msg += f" | 查询参数: {dict(request.query_params)}"
        
        # 添加响应数据（如果有额外信息）
        if 'data' in response_data and response_data['data'] is not None:
            alert_msg += f" | 响应数据: {str(response_data['data'])[:200]}"  # 限制长度
        
        return alert_msg
    
    def _create_log_record(self, message: str, response_code: int) -> logging.LogRecord:
        """
        创建用于告警的日志记录
        
        Args:
            message: 告警消息
            response_code: 响应码
            
        Returns:
            日志记录对象
        """
        # 根据响应码确定日志级别
        if response_code >= 500:
            level = logging.ERROR
        elif response_code >= 400:
            level = logging.WARNING
        else:
            level = logging.WARNING
        
        # 创建日志记录
        record = logging.LogRecord(
            name="api.response_alert",
            level=level,
            pathname=__file__,
            lineno=0,
            msg=message,
            args=(),
            exc_info=None
        )
        
        return record

def register_middleware(app):
    """
    注册响应告警中间件到FastAPI应用
    
    Args:
        app: FastAPI应用实例
    """
    app.add_middleware(ResponseAlertMiddleware)