"""Versioned contracts shared by plans, trial artifacts, and analysis."""

from __future__ import annotations

from collections.abc import Mapping, Sequence
from typing import Any


SCHEMA_VERSION = "1.0.0"
SCHEMA_MAJOR = 1

STORAGE_FORMATS = {
    "plan": "json",
    "batch_manifest": "json",
    "trial_manifest": "json",
    "samples": "numpy-npz",
    "events": "json-lines",
    "trial_metrics": "json-lines",
    "paper_source_data": "csv",
}


class ContractError(ValueError):
    """Raised when an evidence artifact violates its declared contract."""


def require_schema(document: Mapping[str, Any], expected_kind: str) -> None:
    if not isinstance(document, Mapping):
        raise ContractError("document must be a mapping")
    if document.get("kind") != expected_kind:
        raise ContractError(
            f"expected kind {expected_kind!r}, got {document.get('kind')!r}"
        )
    version = document.get("schema_version")
    if not isinstance(version, str):
        raise ContractError("schema_version must be a string")
    try:
        major = int(version.split(".", 1)[0])
    except (TypeError, ValueError) as exc:
        raise ContractError(f"invalid schema_version {version!r}") from exc
    if major != SCHEMA_MAJOR:
        raise ContractError(
            f"unsupported schema major {major}; expected {SCHEMA_MAJOR}"
        )


def require_nonempty_string(value: Any, name: str) -> str:
    if not isinstance(value, str) or not value.strip():
        raise ContractError(f"{name} must be a non-empty string")
    return value


def require_sequence(value: Any, name: str) -> Sequence[Any]:
    if isinstance(value, (str, bytes)) or not isinstance(value, Sequence):
        raise ContractError(f"{name} must be a sequence")
    if not value:
        raise ContractError(f"{name} must not be empty")
    return value
