"""Annotation API for trace and span evaluation."""
from __future__ import annotations

import logging
import threading
from enum import StrEnum
from typing import Any

import httpx

logger = logging.getLogger("staso")

_annotation_client: httpx.Client | None = None
_annotation_client_lock = threading.Lock()


class AnnotationDataType(StrEnum):
    NUMERIC = "numeric"
    CATEGORICAL = "categorical"
    BOOLEAN = "boolean"


def _get_annotation_client(base_url: str, api_key: str) -> httpx.Client:
    global _annotation_client
    if _annotation_client is None:
        with _annotation_client_lock:
            if _annotation_client is None:
                _annotation_client = httpx.Client(
                    timeout=10.0,
                    headers={"X-API-Key": api_key, "Content-Type": "application/json"},
                )
    return _annotation_client


def shutdown_annotation_client() -> None:
    global _annotation_client
    with _annotation_client_lock:
        if _annotation_client is not None:
            try:
                _annotation_client.close()
            except Exception:
                pass
            _annotation_client = None


def annotate(
    *,
    trace_id: str,
    name: str,
    value: float | str | bool,
    data_type: str | AnnotationDataType = AnnotationDataType.NUMERIC,
    span_id: str | None = None,
    comment: str | None = None,
) -> None:
    """Send an annotation for a trace (and optionally a span) to the backend.

    Fire-and-forget: HTTP errors are logged, not raised.
    No-op when the SDK is not initialized.
    """
    from .client import get_client

    client = get_client()
    if client is None:
        logger.warning("staso: annotate() called before init(), ignoring")
        return

    if not name:
        raise ValueError("annotation name must be a non-empty string")

    dt = data_type.value if isinstance(data_type, AnnotationDataType) else data_type
    if dt == "boolean" and not isinstance(value, bool):
        raise ValueError(f"boolean annotation requires bool value, got {type(value).__name__}")
    if dt == "numeric" and (isinstance(value, bool) or not isinstance(value, (int, float))):
        raise ValueError(f"numeric annotation requires int or float value, got {type(value).__name__}")
    if dt == "categorical" and not isinstance(value, str):
        raise ValueError(f"categorical annotation requires str value, got {type(value).__name__}")

    payload: dict[str, Any] = {
        "name": name,
        "value": value,
        "data_type": dt,
    }
    if span_id:
        payload["span_id"] = span_id
    if comment:
        payload["comment"] = comment

    base_url = client.config.base_url.rstrip("/")
    api_key = client.config.api_key
    url = f"{base_url}/v1/traces/{trace_id}/annotations"

    try:
        http_client = _get_annotation_client(base_url, api_key)
        resp = http_client.post(url, json=payload)
        if resp.status_code >= 400:
            logger.warning(
                "staso: annotation POST returned %d – %s",
                resp.status_code,
                resp.text[:300],
            )
        else:
            logger.debug("staso: annotation sent for trace=%s name=%s", trace_id, name)
    except Exception as exc:
        logger.warning("staso: failed to send annotation: %s", exc)
