"""Trace event request and acknowledgement models."""

from __future__ import annotations

from pydantic import (
    BaseModel,
    ConfigDict,
    Field,
    JsonValue,
    field_validator,
    model_validator,
)

from dr_langfuse.errors.error_envelope import ErrorEnvelope
from dr_langfuse.validation import validate_json_safe_dict


class TraceEventRequest(BaseModel):
    """Request contract for creating or updating a trace event."""

    event_name: str = Field(min_length=1)
    session_id: str | None = Field(default=None, min_length=1)
    tags: list[str] = Field(default_factory=list)
    metadata: dict[str, JsonValue] = Field(default_factory=dict)

    @field_validator("metadata")
    @classmethod
    def _ensure_json_safe_metadata(
        cls, metadata: dict[str, JsonValue]
    ) -> dict[str, JsonValue]:
        return validate_json_safe_dict(metadata, prefix="metadata")


class TraceAck(BaseModel):
    """Acknowledgement returned after submitting a trace event."""

    model_config = ConfigDict(frozen=True)

    accepted: bool
    trace_id: str | None = None
    error: ErrorEnvelope | None = None

    @model_validator(mode="after")
    def _reject_accepted_with_error(self) -> TraceAck:
        if self.accepted and self.error is not None:
            raise ValueError("error must be null when accepted is true")
        if not self.accepted and self.error is None:
            raise ValueError("error must be present when accepted is false")
        if self.accepted and not self.trace_id:
            raise ValueError("trace_id must be present when accepted is true")
        if not self.accepted and self.trace_id is not None:
            raise ValueError("trace_id must be absent when accepted is false")
        return self
