# -*- coding: utf-8 -*-
"""
异常/错误全链路追踪 — ERROR span 记录辅助函数

集成到全局异常处理器（http_exception_handler / unhandled_exception_handler），
为 HTTPException 和未捕获异常分别记录 ERROR span。

- HTTPException → ERROR span（异常类型、status_code、detail、发生层级）
- 未捕获异常 → ERROR span（异常类型、消息、堆栈摘要前 5 行）
- 数据库异常（psycopg2.Error）→ DB_ERROR span（错误码、消息、触发 SQL）

所有函数均为安全调用：trace 未激活时静默跳过，不影响请求处理。
"""

from __future__ import annotations

import traceback
from datetime import datetime

from starlette.exceptions import HTTPException

from app.trace.context import SpanType, TraceSpan, get_current_trace


def record_http_exception(exc: HTTPException) -> None:
    """为 HTTPException 记录 ERROR span。

    记录内容：异常类型、status_code、detail、发生层级（exception_handler）。
    trace 未激活时静默跳过。
    """
    ctx = get_current_trace()
    if ctx is None:
        return

    ctx.add_span(TraceSpan(
        span_type=SpanType.ERROR,
        module="trace.error_handler",
        function="record_http_exception",
        description_zh=f"HTTP 异常: {exc.status_code} {exc.detail}",
        description_en=f"HTTP exception: {exc.status_code} {exc.detail}",
        params={},
        result_summary=f"{exc.status_code}",
        duration_ms=0.0,
        timestamp=datetime.now().isoformat(),
        extra={
            "exception_type": type(exc).__name__,
            "status_code": exc.status_code,
            "detail": str(exc.detail) if exc.detail else "",
            "layer": "exception_handler",
        },
    ))


def record_unhandled_exception(exc: Exception) -> None:
    """为未捕获异常记录 ERROR span。

    记录内容：异常类型、消息、堆栈摘要（最后 5 行）。
    trace 未激活时静默跳过。
    """
    ctx = get_current_trace()
    if ctx is None:
        return

    # 堆栈摘要：取最后 5 行，避免 span 过大
    tb_lines = traceback.format_exception(type(exc), exc, exc.__traceback__)
    stack_summary = "".join(tb_lines[-5:]) if len(tb_lines) > 5 else "".join(tb_lines)

    ctx.add_span(TraceSpan(
        span_type=SpanType.ERROR,
        module="trace.error_handler",
        function="record_unhandled_exception",
        description_zh=f"未捕获异常: {type(exc).__name__}: {exc}",
        description_en=f"Unhandled exception: {type(exc).__name__}: {exc}",
        params={},
        result_summary=type(exc).__name__,
        duration_ms=0.0,
        timestamp=datetime.now().isoformat(),
        extra={
            "exception_type": type(exc).__name__,
            "message": str(exc),
            "stack_summary": stack_summary,
            "layer": "exception_handler",
        },
    ))


def record_db_exception(exc: Exception, sql: str = "") -> None:
    """为数据库异常记录 DB_ERROR span。

    记录内容：PostgreSQL 错误码（如有）、消息、触发 SQL。
    trace 未激活时静默跳过。
    """
    ctx = get_current_trace()
    if ctx is None:
        return

    # 尝试提取 psycopg2 错误码
    pgcode = getattr(exc, "pgcode", None) or ""

    ctx.add_span(TraceSpan(
        span_type=SpanType.DB_ERROR,
        module="trace.error_handler",
        function="record_db_exception",
        description_zh=f"数据库异常: {type(exc).__name__}: {exc}",
        description_en=f"Database exception: {type(exc).__name__}: {exc}",
        params={},
        result_summary=type(exc).__name__,
        duration_ms=0.0,
        timestamp=datetime.now().isoformat(),
        extra={
            "exception_type": type(exc).__name__,
            "message": str(exc),
            "pgcode": pgcode,
            "sql": sql,
            "layer": "database",
        },
    ))
