"""Tests for ErrorCode and ErrorEnvelope."""

from __future__ import annotations

import pytest
from pydantic import ValidationError

from dr_langfuse.errors.codes import ErrorCode
from dr_langfuse.errors.error_envelope import ErrorEnvelope


def test_error_envelope_roundtrip() -> None:
    envelope = ErrorEnvelope.model_validate(
        {
            "code": "timeout",
            "message": "request exceeded timeout",
            "retriable": True,
            "details": {"attempt": 2},
        }
    )
    assert envelope.code == ErrorCode.TIMEOUT
    envelope_dump = envelope.model_dump(mode="json")
    assert (
        ErrorEnvelope.model_validate(envelope_dump).model_dump(mode="json")
        == envelope_dump
    )


def test_error_envelope_rejects_unknown_code() -> None:
    with pytest.raises(ValidationError):
        ErrorEnvelope.model_validate({"code": "unknown", "message": "bad"})


def test_error_envelope_rejects_empty_message() -> None:
    with pytest.raises(ValidationError):
        ErrorEnvelope.model_validate({"code": "timeout", "message": ""})


def test_error_envelope_rejects_non_json_details() -> None:
    with pytest.raises(ValidationError):
        ErrorEnvelope.model_validate(
            {"code": "timeout", "message": "bad", "details": {"not_json": object()}}
        )


@pytest.mark.parametrize("val", [float("nan"), float("inf"), float("-inf")])
def test_error_envelope_rejects_nan_in_details(val: float) -> None:
    with pytest.raises(ValidationError):
        ErrorEnvelope.model_validate(
            {"code": "timeout", "message": "bad", "details": {"not_json": val}}
        )


def test_error_envelope_is_immutable() -> None:
    envelope = ErrorEnvelope.model_validate(
        {"code": "timeout", "message": "request exceeded timeout"}
    )
    with pytest.raises((ValidationError, TypeError, AttributeError)):
        envelope.code = None
