"""Structured JSON-lines logging of every model call (charter §10 — the seed and
the full prompt logged with every call; §4 — free eval/replay infrastructure).

One JSON object per line: everything needed to replay the call (canon_log +
messages + model + seed) against a candidate model. No secrets to redact — the
client never sends keys, the canon log carries no PII, and the prompt is exactly
what we want on record.
"""

import json
import sys
from datetime import datetime, timezone
from typing import Callable

from . import config


def _default_write(line: str) -> None:
    """Best-effort (charter §13): a good model call must never become a 500
    because the log write failed (disk full, bad permissions, a misconfigured
    CALL_LOG_PATH). Any failure here is swallowed and reported to stderr —
    never stdout, since stdout may itself be the default sink and must stay
    clean JSON-lines for downstream tooling.
    """
    try:
        path = config.call_log_path()
        if path:
            with open(path, "a", encoding="utf-8") as handle:
                handle.write(line + "\n")
        else:
            sys.stdout.write(line + "\n")
    except Exception as exc:  # noqa: BLE001 - logging must never break a request
        print(f"call_log: failed to write log line: {exc}", file=sys.stderr)


def record(
    *,
    role: str,
    model: str,
    options: dict,
    messages: list[dict],
    canon_log: dict,
    ok: bool,
    latency_ms: int,
    response: str | None = None,
    error: str | None = None,
    write: Callable[[str], None] = _default_write,
) -> dict:
    rec: dict = {
        "ts": datetime.now(timezone.utc).isoformat(),
        "role": role,
        "model": model,
        "options": options,
        "messages": messages,
        "canon_log": canon_log,
        "ok": ok,
        "latency_ms": latency_ms,
    }
    if ok:
        rec["response"] = response
    else:
        rec["error"] = error
    write(json.dumps(rec, ensure_ascii=False))
    return rec
