import json

from app.call_log import record


def test_success_record_shape():
    captured = []
    rec = record(
        role="narrator", model="qwen3.5:latest", options={"seed": 7},
        messages=[{"role": "user", "content": "x"}], canon_log={"a": 1},
        ok=True, latency_ms=120, response="prose", write=captured.append,
    )
    assert len(captured) == 1
    parsed = json.loads(captured[0])
    assert parsed["ok"] is True
    assert parsed["response"] == "prose"
    assert parsed["options"]["seed"] == 7
    assert parsed["role"] == "narrator"
    assert parsed["canon_log"] == {"a": 1}
    assert "error" not in parsed
    assert "ts" in parsed
    assert rec["response"] == "prose"


def test_failure_record_shape():
    captured = []
    record(
        role="narrator", model="m", options={}, messages=[], canon_log={},
        ok=False, latency_ms=5, error="ModelError: down", write=captured.append,
    )
    parsed = json.loads(captured[0])
    assert parsed["ok"] is False
    assert parsed["error"] == "ModelError: down"
    assert "response" not in parsed


def test_default_write_failure_does_not_propagate(monkeypatch, capsys):
    """§13 — a good narration must never become a 500 because the log write
    failed. Point CALL_LOG_PATH at a path whose parent directory does not
    exist, so the default sink's `open()` raises. record() must swallow it,
    report to stderr (never stdout — stdout may be the log sink itself), and
    still return the record.
    """
    monkeypatch.setenv(
        "CALL_LOG_PATH", "/nonexistent-dir-for-test/does/not/exist.log"
    )
    rec = record(
        role="narrator", model="qwen3.5:latest", options={"seed": 7},
        messages=[{"role": "user", "content": "x"}], canon_log={"a": 1},
        ok=True, latency_ms=120, response="prose",
    )
    assert rec["response"] == "prose"
    assert rec["ok"] is True
    out, err = capsys.readouterr()
    assert out == ""
    assert err != ""
