"""Generic file IO helpers for Pydantic-backed models."""

from __future__ import annotations

import json
from pathlib import Path
from typing import TypeVar

import yaml
from pydantic import BaseModel, ValidationError

ModelT = TypeVar("ModelT", bound=BaseModel)


def validate_model(
    data: object, model_type: type[ModelT], error_message: str
) -> ModelT:
    """Validate raw data against a Pydantic model."""
    try:
        return model_type.model_validate(data)
    except ValidationError as exc:
        raise ValueError(error_message) from exc


def load_yaml_model(path: Path, model_type: type[ModelT], error_message: str) -> ModelT:
    """Load and validate a YAML-backed model."""
    with open(path) as handle:
        data = yaml.safe_load(handle) or {}
    return validate_model(data, model_type, error_message)


def store_yaml_model(path: Path, model: BaseModel) -> None:
    """Serialize a model to YAML."""
    with open(path, "w") as handle:
        yaml.safe_dump(
            model.model_dump(mode="json"),
            handle,
            default_flow_style=False,
            sort_keys=False,
        )


def load_json_model(path: Path, model_type: type[ModelT], error_message: str) -> ModelT:
    """Load and validate a JSON-backed model."""
    with open(path) as handle:
        data = json.load(handle)
    return validate_model(data, model_type, error_message)


def store_json_model(path: Path, model: BaseModel) -> None:
    """Serialize a model to JSON."""
    with open(path, "w") as handle:
        json.dump(model.model_dump(mode="json"), handle, indent=2, sort_keys=True)
