"""Tests for TraceEventRequest and TraceAck."""

from __future__ import annotations

import pytest
from pydantic import ValidationError

from dr_langfuse.tracing.models import TraceAck, TraceEventRequest


def test_trace_event_request_roundtrip() -> None:
    trace = TraceEventRequest.model_validate(
        {
            "event_name": "docker.run",
            "session_id": "session-123",
            "tags": ["runtime", "docker"],
            "metadata": {"attempt": 1},
        }
    )
    trace_dump = trace.model_dump(mode="json")
    assert (
        TraceEventRequest.model_validate(trace_dump).model_dump(mode="json")
        == trace_dump
    )


def test_trace_event_request_rejects_empty_name() -> None:
    with pytest.raises(ValidationError):
        TraceEventRequest.model_validate({"event_name": ""})


def test_trace_event_request_rejects_empty_session_id() -> None:
    with pytest.raises(ValidationError):
        TraceEventRequest.model_validate({"event_name": "x", "session_id": ""})


def test_trace_event_request_rejects_non_json_metadata() -> None:
    with pytest.raises(ValidationError):
        TraceEventRequest.model_validate(
            {"event_name": "x", "metadata": {"bad": object()}}
        )


@pytest.mark.parametrize(
    "bad_value",
    [float("inf"), float("nan"), float("-inf")],
    ids=["inf", "nan", "neg_inf"],
)
def test_trace_event_request_rejects_non_finite_metadata(bad_value: float) -> None:
    """math.isfinite rejects all non-finite floats; metadata must be JSON-safe."""
    with pytest.raises(ValidationError):
        TraceEventRequest.model_validate(
            {"event_name": "x", "metadata": {"bad": bad_value}}
        )


def test_trace_ack_accepts_accepted_no_error() -> None:
    ack = TraceAck.model_validate({"accepted": True, "trace_id": "trace-abc"})
    assert ack.accepted is True
    assert ack.error is None


def test_trace_ack_accepts_rejected_with_error() -> None:
    ack = TraceAck.model_validate(
        {"accepted": False, "error": {"code": "timeout", "message": "timed out"}}
    )
    assert ack.accepted is False
    assert ack.error is not None


def test_trace_ack_rejects_accepted_with_error() -> None:
    with pytest.raises(ValidationError):
        TraceAck.model_validate(
            {
                "accepted": True,
                "error": {
                    "code": "internal_error",
                    "message": "should not be present on accepted trace",
                },
            }
        )


def test_trace_ack_rejects_accepted_without_trace_id() -> None:
    with pytest.raises(ValidationError):
        TraceAck.model_validate({"accepted": True})


def test_trace_ack_rejects_rejected_without_error() -> None:
    with pytest.raises(ValidationError):
        TraceAck.model_validate({"accepted": False})


def test_trace_ack_rejects_rejected_with_trace_id() -> None:
    with pytest.raises(ValidationError):
        TraceAck.model_validate(
            {
                "accepted": False,
                "trace_id": "trace-abc",
                "error": {"code": "internal_error", "message": "failed"},
            }
        )
