"""Payload schemas and validation helpers for eval results."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, TypedDict, cast

from pydantic import BaseModel, ConfigDict, Field, ValidationError

from .exceptions import PayloadFormatError


if TYPE_CHECKING:
    from collections.abc import Iterable


class _MetricRecordRequired(TypedDict):
    """Normalized record schema for metrics payload."""

    category: str
    splitType: str
    metricName: str
    metricValue: float


class MetricRecord(_MetricRecordRequired, total=False):
    """Metric record including optional contextual attributes."""

    note: str
    taskType: str
    runtimeFramework: str


MetricPayload = list[MetricRecord]


class MetricRecordModel(BaseModel):
    """Pydantic schema used for metric payload validation."""

    model_config = ConfigDict(extra="forbid", str_strip_whitespace=True, populate_by_name=True)

    category: str = Field(min_length=1)
    split_type: str = Field(min_length=1, alias="splitType")
    metric_name: str = Field(min_length=1, alias="metricName")
    metric_value: float = Field(alias="metricValue")
    note: str | None = None
    task_type: str | None = Field(default=None, alias="taskType")
    runtime_framework: str | None = Field(default=None, alias="runtimeFramework")


def validate_metric_record(item: dict[str, Any], index: int = 0) -> MetricRecord:
    """Validate and normalize a metric record with Pydantic.

    Args:
        item: Raw metric record dictionary to validate.
        index: Item index used for contextual error messages.

    Returns:
        Normalized metric record that conforms to payload schema.
    """
    try:
        model = MetricRecordModel.model_validate(item)
    except ValidationError as exc:
        raise PayloadFormatError(
            f"Metric payload item #{index} failed schema validation: {exc}"
        ) from exc

    normalized = model.model_dump(by_alias=True, exclude_none=True)
    return cast("MetricRecord", normalized)


def validate_payload(payload: Iterable[dict[str, Any]]) -> MetricPayload:
    """Validate and normalize a full metric payload list with Pydantic.

    Args:
        payload: Iterable of raw metric record dictionaries.

    Returns:
        List of normalized metric records.
    """
    normalized: MetricPayload = []
    for idx, item in enumerate(payload):
        if not isinstance(item, dict):
            raise PayloadFormatError(
                f"Metric payload item #{idx} must be dict, got {type(item).__name__}"
            )
        normalized.append(validate_metric_record(item, idx))
    return normalized

