"""
全局异常捕获中间件

两层防线确保异常上报到 Log Center：
1. got_request_exception 信号 —— 捕获被 Django convert_exception_to_response 吞掉的异常
   （如 CommonMiddleware 的 APPEND_SLASH RuntimeError）
2. ExceptionReportMiddleware 的 try/except —— 兜底捕获穿透所有内层包裹的异常
"""
import os
import sys
import traceback
import threading
import requests
from django.http import JsonResponse
from django.core.signals import got_request_exception


LOG_CENTER_URL = os.environ.get('LOG_CENTER_URL', 'https://qiyuan-log-center-api.airlabs.art')
LOG_CENTER_ENABLED = os.environ.get('LOG_CENTER_ENABLED', 'true').lower() == 'true'


def _send_to_log_center(payload):
    """异步发送日志到 Log Center"""
    def send_async():
        try:
            requests.post(
                f"{LOG_CENTER_URL}/api/v1/logs/report",
                json=payload,
                timeout=3,
            )
        except Exception:
            pass

    thread = threading.Thread(target=send_async)
    thread.daemon = True
    thread.start()


def _report_exception(exc, request):
    """构造 payload 并上报异常"""
    if not LOG_CENTER_ENABLED:
        return

    try:
        tb = traceback.extract_tb(exc.__traceback__) if exc.__traceback__ else []
        last_frame = tb[-1] if tb else None

        payload = {
            "project_id": "rtc_backend",
            "environment": os.environ.get('ENVIRONMENT', 'development'),
            "level": "ERROR",
            "repo_url": "https://gitea.airlabs.art/zyc/rtc_backend.git",
            "error": {
                "type": type(exc).__name__,
                "message": str(exc),
                "file_path": last_frame.filename if last_frame else "unknown",
                "line_number": last_frame.lineno if last_frame else 0,
                "stack_trace": traceback.format_exception(exc) if exc.__traceback__ else [str(exc)],
            },
            "context": {
                "url": request.path,
                "method": request.method,
                "view": "middleware",
            },
        }
        _send_to_log_center(payload)
    except Exception:
        pass


def _on_request_exception(sender, request, **kwargs):
    """
    Django 信号回调：convert_exception_to_response 内部触发。
    此时 sys.exc_info() 仍持有完整的异常上下文。
    """
    exc_info = sys.exc_info()
    exc = exc_info[1]
    if exc:
        _report_exception(exc, request)


# 模块加载时注册信号，全局生效
got_request_exception.connect(_on_request_exception)


class TrailingSlashMiddleware:
    """
    为缺少尾部斜杠的 API 请求补全 '/'，直接修改 request.path_info，
    不做 HTTP 重定向，因此 POST/PUT/PATCH 请求体完好保留。

    配合 APPEND_SLASH = False 使用，替代 CommonMiddleware 的重定向逻辑。
    必须放在 CommonMiddleware 之前。
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if not request.path_info.endswith('/'):
            request.path_info = request.path_info + '/'
        return self.get_response(request)


class ExceptionReportMiddleware:
    """
    全局异常捕获中间件，必须放在 MIDDLEWARE 列表的第一个位置。

    作为第二道防线：如果异常穿过了所有内层中间件的
    convert_exception_to_response 包裹，这里的 try/except 仍会兜底。
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        try:
            response = self.get_response(request)
            return response
        except Exception as exc:
            _report_exception(exc, request)
            return JsonResponse(
                {"code": 1, "message": str(exc), "data": None},
                status=500,
            )
