"""Internal input validation helpers (pydantic-optional)."""

from __future__ import annotations

import inspect
import typing
from typing import Any

import restate


def get_input_model(fn: Any, param_index: int = 1) -> type | None:
    """Extract a pydantic BaseModel from a parameter's type hint.

    *param_index* is the 0-based position of the input parameter
    (default ``1`` for ``(ctx, input)``; use ``2`` for virtual object
    exclusive handlers ``(saga, ctx, input)``).

    Returns ``None`` if pydantic is not installed or the annotation is not a
    BaseModel subclass.
    """
    try:
        from pydantic import BaseModel
    except ImportError:
        return None

    try:
        hints = typing.get_type_hints(fn)
    except Exception:
        return None

    params = list(inspect.signature(fn).parameters.keys())
    if len(params) > param_index:
        input_type = hints.get(params[param_index])
        if (
            input_type is not None
            and isinstance(input_type, type)
            and issubclass(input_type, BaseModel)
        ):
            return input_type
    return None


def validate_input(input_val: Any, model: type | None, name: str) -> Any:
    """Validate *input_val* against a pydantic model.

    Returns the validated model instance, or *input_val* unchanged if no model
    is configured.  Raises ``TerminalError`` on validation failure (bad input
    won't fix itself on retry).
    """
    if model is None:
        return input_val

    # Already the right type — no conversion needed
    if isinstance(input_val, model):
        return input_val

    from pydantic import ValidationError

    try:
        return model.model_validate(input_val)
    except ValidationError as e:
        raise restate.TerminalError(
            f"Input validation failed for {name}: {e}"
        ) from e
