"""KAR-744 — gemeinsamer LLM-Call-Tracer fuer Aria.

Schreibt eine JSONL-Zeile pro Anthropic-Call nach /root/aria/logs/llm-traces.jsonl
(Prompt, Response, Model, Tokens, Latenz, Fehler). Forensik-tauglich + Quelle fuer
Eval-Golden-Sets (KAR-745).

Fail-safe: wirft NIE — Tracing darf die Pipeline nicht brechen.
Toggle: ARIA_LLM_TRACE=0 schaltet aus (Default an). Pfad: ARIA_LLM_TRACE_PATH.

Genutzt von aria-akp-deep.call_opus, aria-akp-triage.call_haiku (+ kuenftig vision).
"""
from __future__ import annotations
import json
import os
from datetime import datetime, timezone
from pathlib import Path

TRACE_PATH = Path(os.environ.get("ARIA_LLM_TRACE_PATH", "/root/aria/logs/llm-traces.jsonl"))
_MAX_BYTES = 50 * 1024 * 1024   # 50 MB -> rotate auf .1
_FIELD_CAP = 500_000            # pro Feld harte Obergrenze gegen Riesen-Zeilen


def _cap(value, n: int = _FIELD_CAP):
    if value is None:
        return None
    s = str(value)
    if len(s) <= n:
        return s
    return s[:n] + f"...<truncated {len(s) - n} chars>"


def _rotate_if_needed() -> None:
    try:
        if TRACE_PATH.exists() and TRACE_PATH.stat().st_size > _MAX_BYTES:
            bak = TRACE_PATH.with_name(TRACE_PATH.name + ".1")
            if bak.exists():
                bak.unlink()
            TRACE_PATH.rename(bak)
    except OSError:
        pass


def trace_llm_call(*, script: str, model: str, prompt, response_text=None,
                   usage=None, latency_ms=None, correlation_id=None,
                   video_id=None, error=None) -> None:
    """Haengt eine JSONL-Trace-Zeile an. Wirft nie."""
    if os.environ.get("ARIA_LLM_TRACE", "1") == "0":
        return
    try:
        usage = usage or {}
        rec = {
            "ts": datetime.now(timezone.utc).isoformat(),
            "script": script,
            "model": model,
            "video_id": video_id,
            "correlation_id": correlation_id,
            "input_tokens": usage.get("input_tokens"),
            "output_tokens": usage.get("output_tokens"),
            "latency_ms": latency_ms,
            "error": _cap(error, 2000),
            "prompt": _cap(prompt),
            "response": _cap(response_text),
        }
        TRACE_PATH.parent.mkdir(parents=True, exist_ok=True)
        _rotate_if_needed()
        with TRACE_PATH.open("a", encoding="utf-8") as f:
            f.write(json.dumps(rec, ensure_ascii=False) + "\n")
    except Exception:
        # Tracing darf die Pipeline nie brechen
        pass
