"""Tests for pydantic input validation."""

import pytest
import restate
from pydantic import BaseModel

from restate_saga._validation import get_input_model, validate_input


# ---------------------------------------------------------------------------
# get_input_model
# ---------------------------------------------------------------------------


class MyInput(BaseModel):
    name: str
    count: int = 0


async def fn_with_model(ctx, input_val: MyInput):
    pass


async def fn_without_annotation(ctx, input_val):
    pass


async def fn_with_plain_type(ctx, input_val: dict):
    pass


def test_detects_pydantic_model():
    assert get_input_model(fn_with_model) is MyInput


def test_returns_none_for_no_annotation():
    assert get_input_model(fn_without_annotation) is None


def test_returns_none_for_plain_type():
    assert get_input_model(fn_with_plain_type) is None


# ---------------------------------------------------------------------------
# validate_input
# ---------------------------------------------------------------------------


def test_validates_dict_to_model():
    result = validate_input({"name": "alice", "count": 3}, MyInput, "TestStep")
    assert isinstance(result, MyInput)
    assert result.name == "alice"
    assert result.count == 3


def test_passes_through_model_instance():
    instance = MyInput(name="bob")
    result = validate_input(instance, MyInput, "TestStep")
    assert result is instance


def test_applies_defaults():
    result = validate_input({"name": "carol"}, MyInput, "TestStep")
    assert result.count == 0


def test_raises_terminal_error_on_invalid_input():
    with pytest.raises(restate.TerminalError, match="Input validation failed"):
        validate_input({"count": "not_a_number"}, MyInput, "TestStep")


def test_raises_terminal_error_on_missing_required():
    with pytest.raises(restate.TerminalError, match="Input validation failed"):
        validate_input({}, MyInput, "TestStep")


def test_no_model_passes_through():
    raw = {"anything": True}
    result = validate_input(raw, None, "TestStep")
    assert result is raw
