"""
Anthropic 라이브러리 자동 패치
Anthropic API 호출을 자동으로 trace합니다.
"""

import time
from typing import Any, Optional, Dict
from functools import wraps

from ..client import get_client
from ..utils import format_messages, safe_extract_attr


def patch_anthropic() -> None:
    """Anthropic 라이브러리를 패치하여 자동 trace를 활성화합니다."""
    try:
        import anthropic
    except ImportError:
        return  # Anthropic이 설치되지 않은 경우 무시

    # 이미 패치되었는지 확인
    if hasattr(anthropic, "_nora_patched"):
        return

    # 원본 메서드 저장
    original_messages_create = anthropic.Anthropic.messages.create

    # 동기 버전 패치
    @wraps(original_messages_create)
    def patched_messages_create_sync(self, *args, **kwargs):
        """동기 Messages API 패치"""
        return _trace_anthropic_call(original_messages_create, self, args, kwargs, is_async=False)

    # 비동기 버전 패치
    @wraps(original_messages_create)
    async def patched_messages_create_async(self, *args, **kwargs):
        """비동기 Messages API 패치"""
        return await _trace_anthropic_call(
            original_messages_create, self, args, kwargs, is_async=True
        )

    # 패치 적용
    anthropic.Anthropic.messages.create = patched_messages_create_sync

    # 비동기 버전이 있으면 패치
    if hasattr(anthropic, "AsyncAnthropic"):
        try:
            anthropic.AsyncAnthropic.messages.create = patched_messages_create_async
        except AttributeError:
            pass

    # 패치 완료 표시
    anthropic._nora_patched = True


async def _trace_anthropic_call(original_func, self, args, kwargs, is_async: bool):
    """Anthropic 호출을 trace합니다."""
    client = get_client()
    if not client or not client.enabled:
        if is_async:
            return await original_func(self, *args, **kwargs)
        return original_func(self, *args, **kwargs)

    start_time = time.time()
    model = kwargs.get("model", "unknown")
    messages = kwargs.get("messages", [])
    prompt = format_messages(messages)

    try:
        # 원본 함수 호출
        if is_async:
            response = await original_func(self, *args, **kwargs)
        else:
            response = original_func(self, *args, **kwargs)

        end_time = time.time()

        # 응답 데이터 추출
        response_text = _extract_response_text(response)
        tokens_used = _extract_tokens(response)

        # Trace 기록
        client.trace(
            provider="anthropic",
            model=model,
            prompt=prompt,
            response=response_text,
            start_time=start_time,
            end_time=end_time,
            tokens_used=tokens_used,
            metadata=_build_metadata(kwargs, messages),
        )

        return response

    except Exception as e:
        end_time = time.time()

        # 에러도 trace에 기록
        client.trace(
            provider="anthropic",
            model=model,
            prompt=prompt,
            start_time=start_time,
            end_time=end_time,
            error=str(e),
            metadata={"messages": messages},
        )
        raise


def _extract_response_text(response: Any) -> str:
    """Anthropic 응답 객체에서 텍스트를 추출합니다."""
    try:
        if hasattr(response, "content"):
            content = response.content
            if isinstance(content, list) and content:
                first_block = content[0]
                if hasattr(first_block, "text"):
                    return first_block.text
                elif isinstance(first_block, dict) and first_block.get("type") == "text":
                    return first_block.get("text", "")
        return ""
    except Exception:
        return ""


def _extract_tokens(response: Any) -> Optional[int]:
    """Anthropic 응답 객체에서 토큰 사용량을 추출합니다."""
    try:
        usage = safe_extract_attr(response, "usage")
        if usage:
            input_tokens = safe_extract_attr(usage, "input_tokens", default=0)
            output_tokens = safe_extract_attr(usage, "output_tokens", default=0)
            return input_tokens + output_tokens
        return None
    except Exception:
        return None


def _build_metadata(kwargs: Dict[str, Any], messages: list) -> Dict[str, Any]:
    """메타데이터를 구성합니다."""
    return {
        "messages": messages,
        "temperature": kwargs.get("temperature"),
        "max_tokens": kwargs.get("max_tokens"),
        "top_p": kwargs.get("top_p"),
        "top_k": kwargs.get("top_k"),
    }
