"""Tests for Load Value node."""

import pytest

from fw_nodes_core.nodes.load_value import LoadValueNode, LoadValueOutput


@pytest.mark.asyncio
async def test_load_existing_value(mock_context):
    """Test loading an existing value."""
    mock_context._data_store["greeting"] = "hello"
    node = LoadValueNode()

    result = await node.execute({"key": "greeting", "type": "string"}, mock_context)

    assert isinstance(result, LoadValueOutput)
    assert result.key == "greeting"
    assert result.value == "hello"
    assert result.found is True


@pytest.mark.asyncio
async def test_load_missing_key_returns_none(mock_context):
    """Test loading a key that doesn't exist returns None."""
    node = LoadValueNode()

    result = await node.execute({"key": "nonexistent", "type": "string"}, mock_context)

    assert result.key == "nonexistent"
    assert result.value is None
    assert result.found is False


@pytest.mark.asyncio
async def test_load_missing_key_with_default(mock_context):
    """Test loading a missing key uses the default value."""
    node = LoadValueNode()

    result = await node.execute(
        {"key": "nonexistent", "type": "string", "default": "fallback"},
        mock_context,
    )

    assert result.value == "fallback"
    assert result.found is False


@pytest.mark.asyncio
async def test_load_cast_number_int(mock_context):
    """Test casting a stored value to integer."""
    mock_context._data_store["count"] = "42"
    node = LoadValueNode()

    result = await node.execute({"key": "count", "type": "number"}, mock_context)

    assert result.value == 42
    assert isinstance(result.value, int)


@pytest.mark.asyncio
async def test_load_cast_number_float(mock_context):
    """Test casting a stored value to float."""
    mock_context._data_store["ratio"] = "3.14"
    node = LoadValueNode()

    result = await node.execute({"key": "ratio", "type": "number"}, mock_context)

    assert result.value == 3.14
    assert isinstance(result.value, float)


@pytest.mark.asyncio
async def test_load_cast_boolean_true(mock_context):
    """Test casting to boolean (true variants)."""
    node = LoadValueNode()

    for val in ["true", "True", "1", "yes"]:
        mock_context._data_store["flag"] = val
        result = await node.execute({"key": "flag", "type": "boolean"}, mock_context)
        assert result.value is True, f"Expected True for '{val}'"


@pytest.mark.asyncio
async def test_load_cast_boolean_false(mock_context):
    """Test casting to boolean (false variants)."""
    node = LoadValueNode()

    for val in ["false", "False", "0", "no"]:
        mock_context._data_store["flag"] = val
        result = await node.execute({"key": "flag", "type": "boolean"}, mock_context)
        assert result.value is False, f"Expected False for '{val}'"


@pytest.mark.asyncio
async def test_load_cast_number_fails(mock_context):
    """Test that casting a non-numeric string to number raises an error."""
    mock_context._data_store["bad"] = "not_a_number"
    node = LoadValueNode()

    with pytest.raises(ValueError, match="Cannot cast"):
        await node.execute({"key": "bad", "type": "number"}, mock_context)


@pytest.mark.asyncio
async def test_load_cast_boolean_fails(mock_context):
    """Test that casting an invalid string to boolean raises an error."""
    mock_context._data_store["bad"] = "maybe"
    node = LoadValueNode()

    with pytest.raises(ValueError, match="Cannot cast"):
        await node.execute({"key": "bad", "type": "boolean"}, mock_context)


@pytest.mark.asyncio
async def test_load_auto_detects_boolean(mock_context):
    """Test auto type detection for booleans."""
    mock_context._data_store["flag"] = "true"
    node = LoadValueNode()

    result = await node.execute({"key": "flag", "type": "auto"}, mock_context)

    assert result.value is True


@pytest.mark.asyncio
async def test_load_auto_detects_integer(mock_context):
    """Test auto type detection for integers."""
    mock_context._data_store["count"] = "99"
    node = LoadValueNode()

    result = await node.execute({"key": "count", "type": "auto"}, mock_context)

    assert result.value == 99
    assert isinstance(result.value, int)


@pytest.mark.asyncio
async def test_load_auto_detects_float(mock_context):
    """Test auto type detection for floats."""
    mock_context._data_store["ratio"] = "1.5"
    node = LoadValueNode()

    result = await node.execute({"key": "ratio", "type": "auto"}, mock_context)

    assert result.value == 1.5
    assert isinstance(result.value, float)


@pytest.mark.asyncio
async def test_load_auto_falls_back_to_string(mock_context):
    """Test auto type detection falls back to string."""
    mock_context._data_store["name"] = "hello world"
    node = LoadValueNode()

    result = await node.execute({"key": "name", "type": "auto"}, mock_context)

    assert result.value == "hello world"
    assert isinstance(result.value, str)
