"""
Tests for dict data type - creation, data() with orient options.

Dict type stores multiple named columns in a single row.
"""

from aaiclick import ORIENT_DICT, ORIENT_RECORDS, create_object_from_value

# =============================================================================
# Dict Creation Tests
# =============================================================================


async def test_dict_creation_simple(ctx):
    """Test creating a dict object with simple values."""
    obj = await create_object_from_value({"id": 1, "name": "Alice", "age": 30})

    data = await obj.data()

    assert isinstance(data, dict)
    assert data["id"] == 1
    assert data["name"] == "Alice"
    assert data["age"] == 30


async def test_dict_creation_mixed_types(ctx):
    """Test creating a dict with mixed value types."""
    obj = await create_object_from_value({"count": 42, "price": 19.99, "name": "item"})

    data = await obj.data()

    assert data["count"] == 42
    assert data["price"] == 19.99
    assert data["name"] == "item"


async def test_dict_creation_all_int(ctx):
    """Test creating a dict with all integer values."""
    obj = await create_object_from_value({"x": 10, "y": 20, "z": 30})

    data = await obj.data()

    assert data == {"x": 10, "y": 20, "z": 30}


async def test_dict_creation_all_float(ctx):
    """Test creating a dict with all float values."""
    obj = await create_object_from_value({"a": 1.1, "b": 2.2, "c": 3.3})

    data = await obj.data()

    assert data == {"a": 1.1, "b": 2.2, "c": 3.3}


async def test_dict_creation_all_string(ctx):
    """Test creating a dict with all string values."""
    obj = await create_object_from_value({"first": "hello", "second": "world", "third": "test"})

    data = await obj.data()

    assert data["first"] == "hello"
    assert data["second"] == "world"
    assert data["third"] == "test"


# =============================================================================
# Orient Options Tests
# =============================================================================


async def test_dict_orient_dict(ctx):
    """Test data() with orient=ORIENT_DICT returns dict."""
    obj = await create_object_from_value({"x": 10, "y": 20})

    data = await obj.data(orient=ORIENT_DICT)

    assert isinstance(data, dict)
    assert data == {"x": 10, "y": 20}


async def test_dict_orient_records(ctx):
    """Test data() with orient=ORIENT_RECORDS returns list of dicts."""
    obj = await create_object_from_value({"x": 10, "y": 20})

    data = await obj.data(orient=ORIENT_RECORDS)

    assert isinstance(data, list)
    assert len(data) == 1
    assert data[0] == {"x": 10, "y": 20}


async def test_dict_default_orient_is_dict(ctx):
    """Test that default orient is ORIENT_DICT."""
    obj = await create_object_from_value({"a": 1, "b": 2})

    data_default = await obj.data()
    data_explicit = await obj.data(orient=ORIENT_DICT)

    assert data_default == data_explicit


# =============================================================================
# Edge Cases
# =============================================================================


async def test_dict_single_field(ctx):
    """Test dict with a single field."""
    obj = await create_object_from_value({"only": 42})

    data = await obj.data()

    assert data == {"only": 42}


async def test_dict_with_empty_string(ctx):
    """Test dict containing empty string value."""
    obj = await create_object_from_value({"name": "", "value": 123})

    data = await obj.data()

    assert data["name"] == ""
    assert data["value"] == 123


async def test_dict_with_zero_values(ctx):
    """Test dict containing zero values."""
    obj = await create_object_from_value({"zero_int": 0, "zero_float": 0.0})

    data = await obj.data()

    assert data["zero_int"] == 0
    assert data["zero_float"] == 0.0


# =============================================================================
# Dict of Arrays Tests
# =============================================================================


async def test_dict_of_arrays_creation(ctx):
    """Test creating a dict with array values."""
    obj = await create_object_from_value({"id": [1, 2, 3], "value": [10, 20, 30]})

    data = await obj.data()

    assert isinstance(data, dict)
    assert data["id"] == [1, 2, 3]
    assert data["value"] == [10, 20, 30]


async def test_dict_of_arrays_orient_dict(ctx):
    """Test dict of arrays with orient=ORIENT_DICT returns dict with arrays."""
    obj = await create_object_from_value({"name": ["Alice", "Bob"], "age": [30, 25]})

    data = await obj.data(orient=ORIENT_DICT)

    assert isinstance(data, dict)
    assert data["name"] == ["Alice", "Bob"]
    assert data["age"] == [30, 25]


async def test_dict_of_arrays_orient_records(ctx):
    """Test dict of arrays with orient=ORIENT_RECORDS returns list of row dicts."""
    obj = await create_object_from_value({"name": ["Alice", "Bob", "Charlie"], "age": [30, 25, 35]})

    data = await obj.data(orient=ORIENT_RECORDS)

    assert isinstance(data, list)
    assert len(data) == 3
    assert data[0] == {"name": "Alice", "age": 30}
    assert data[1] == {"name": "Bob", "age": 25}
    assert data[2] == {"name": "Charlie", "age": 35}


async def test_dict_of_arrays_floats(ctx):
    """Test dict with float arrays."""
    obj = await create_object_from_value({"x": [1.5, 2.5, 3.5], "y": [4.5, 5.5, 6.5]})

    data = await obj.data()

    assert data["x"] == [1.5, 2.5, 3.5]
    assert data["y"] == [4.5, 5.5, 6.5]


async def test_dict_of_arrays_strings(ctx):
    """Test dict with string arrays."""
    obj = await create_object_from_value({"first": ["John", "Jane"], "last": ["Doe", "Smith"]})

    data = await obj.data()

    assert data["first"] == ["John", "Jane"]
    assert data["last"] == ["Doe", "Smith"]


async def test_dict_of_arrays_records_preserves_order(ctx):
    """Test that orient=ORIENT_RECORDS preserves array order."""
    obj = await create_object_from_value({"letter": ["z", "a", "m"], "number": [3, 1, 2]})

    data = await obj.data(orient=ORIENT_RECORDS)

    # Order should match original array order
    assert data[0] == {"letter": "z", "number": 3}
    assert data[1] == {"letter": "a", "number": 1}
    assert data[2] == {"letter": "m", "number": 2}
