"""Unit tests for vector normalization utilities."""

import pytest

from pinecone._internal.vector_normalization import normalize_vector, normalize_vectors


def test_normalize_dict_unchanged():
    """Dict vectors should pass through unchanged."""
    vector = {"id": "v1", "values": [0.1, 0.2]}
    assert normalize_vector(vector) == vector


def test_normalize_dict_with_metadata():
    """Dict vectors with metadata should pass through unchanged."""
    vector = {"id": "v1", "values": [0.1, 0.2], "metadata": {"key": "val"}}
    assert normalize_vector(vector) == vector


def test_normalize_dict_with_sparse_values():
    """Dict vectors with sparse values should pass through unchanged."""
    vector = {
        "id": "v1",
        "values": [0.1, 0.2],
        "sparseValues": {"indices": [0, 1], "values": [0.5, 0.5]},
    }
    assert normalize_vector(vector) == vector


def test_normalize_2_tuple():
    """2-tuple should be converted to dict."""
    vector = ("v1", [0.1, 0.2])
    expected = {"id": "v1", "values": [0.1, 0.2]}
    assert normalize_vector(vector) == expected


def test_normalize_2_tuple_with_empty_values():
    """2-tuple with empty values should work."""
    vector = ("v1", [])
    expected = {"id": "v1", "values": []}
    assert normalize_vector(vector) == expected


def test_normalize_3_tuple():
    """3-tuple should be converted to dict with metadata."""
    vector = ("v1", [0.1, 0.2], {"key": "val"})
    expected = {"id": "v1", "values": [0.1, 0.2], "metadata": {"key": "val"}}
    assert normalize_vector(vector) == expected


def test_normalize_3_tuple_with_empty_metadata():
    """3-tuple with empty metadata should work."""
    vector = ("v1", [0.1, 0.2], {})
    expected = {"id": "v1", "values": [0.1, 0.2], "metadata": {}}
    assert normalize_vector(vector) == expected


def test_normalize_3_tuple_with_complex_metadata():
    """3-tuple with complex metadata should work."""
    metadata = {
        "string": "value",
        "number": 42,
        "float": 3.14,
        "bool": True,
        "list": ["a", "b", "c"],
    }
    vector = ("v1", [0.1, 0.2], metadata)
    expected = {"id": "v1", "values": [0.1, 0.2], "metadata": metadata}
    assert normalize_vector(vector) == expected


def test_normalize_invalid_tuple_length_1():
    """1-tuple should raise ValueError."""
    with pytest.raises(ValueError, match=r"Tuple vectors must be 2-tuple.*got 1-tuple"):
        normalize_vector(("v1",))


def test_normalize_invalid_tuple_length_4():
    """4-tuple should raise ValueError."""
    with pytest.raises(ValueError, match=r"Tuple vectors must be 2-tuple.*got 4-tuple"):
        normalize_vector(("v1", [0.1], {}, "extra"))


def test_normalize_invalid_type_string():
    """String should raise ValueError."""
    with pytest.raises(ValueError, match=r"must be dict or tuple.*got str"):
        normalize_vector("invalid")


def test_normalize_invalid_type_list():
    """List should raise ValueError."""
    with pytest.raises(ValueError, match=r"must be dict or tuple.*got list"):
        normalize_vector(["v1", [0.1, 0.2]])


def test_normalize_invalid_type_none():
    """None should raise ValueError."""
    with pytest.raises(ValueError, match=r"must be dict or tuple.*got NoneType"):
        normalize_vector(None)


def test_normalize_vectors_empty_list():
    """Empty list should return empty list."""
    assert normalize_vectors([]) == []


def test_normalize_vectors_mixed_formats():
    """Mixed formats should all be normalized to dicts."""
    vectors = [
        {"id": "v1", "values": [0.1]},
        ("v2", [0.2]),
        ("v3", [0.3], {"key": "val"}),
    ]
    result = normalize_vectors(vectors)
    assert len(result) == 3
    assert result[0] == {"id": "v1", "values": [0.1]}
    assert result[1] == {"id": "v2", "values": [0.2]}
    assert result[2] == {"id": "v3", "values": [0.3], "metadata": {"key": "val"}}


def test_normalize_vectors_all_dicts():
    """All dicts should pass through unchanged."""
    vectors = [
        {"id": "v1", "values": [0.1]},
        {"id": "v2", "values": [0.2], "metadata": {"key": "val"}},
    ]
    result = normalize_vectors(vectors)
    assert result == vectors


def test_normalize_vectors_all_2_tuples():
    """All 2-tuples should be converted to dicts."""
    vectors = [
        ("v1", [0.1]),
        ("v2", [0.2]),
    ]
    result = normalize_vectors(vectors)
    assert result == [
        {"id": "v1", "values": [0.1]},
        {"id": "v2", "values": [0.2]},
    ]


def test_normalize_vectors_all_3_tuples():
    """All 3-tuples should be converted to dicts."""
    vectors = [
        ("v1", [0.1], {"key1": "val1"}),
        ("v2", [0.2], {"key2": "val2"}),
    ]
    result = normalize_vectors(vectors)
    assert result == [
        {"id": "v1", "values": [0.1], "metadata": {"key1": "val1"}},
        {"id": "v2", "values": [0.2], "metadata": {"key2": "val2"}},
    ]


def test_normalize_vectors_propagates_errors():
    """Invalid vector in list should propagate error."""
    vectors = [
        {"id": "v1", "values": [0.1]},
        "invalid",
    ]
    with pytest.raises(ValueError, match=r"must be dict or tuple"):
        normalize_vectors(vectors)


def test_normalize_2_tuple_invalid_id_type():
    """2-tuple with non-string ID should raise ValueError."""
    with pytest.raises(ValueError, match=r"Vector ID must be a string"):
        normalize_vector((123, [0.1, 0.2]))


def test_normalize_2_tuple_invalid_values_type():
    """2-tuple with non-list values should raise ValueError."""
    with pytest.raises(ValueError, match=r"Vector values must be a list"):
        normalize_vector(("v1", "not a list"))


def test_normalize_3_tuple_invalid_id_type():
    """3-tuple with non-string ID should raise ValueError."""
    with pytest.raises(ValueError, match=r"Vector ID must be a string"):
        normalize_vector((123, [0.1, 0.2], {"key": "val"}))


def test_normalize_3_tuple_invalid_values_type():
    """3-tuple with non-list values should raise ValueError."""
    with pytest.raises(ValueError, match=r"Vector values must be a list"):
        normalize_vector(("v1", "not a list", {"key": "val"}))


def test_normalize_3_tuple_invalid_metadata_type():
    """3-tuple with non-dict metadata should raise ValueError."""
    with pytest.raises(ValueError, match=r"Vector metadata must be a dict"):
        normalize_vector(("v1", [0.1, 0.2], "not a dict"))


def test_normalize_vectors_all_dicts_no_copy():
    """All-dict input should return same list (performance optimization)."""
    vectors = [
        {"id": "v1", "values": [0.1]},
        {"id": "v2", "values": [0.2]},
    ]
    result = normalize_vectors(vectors)
    # Should return the same list object (not a copy)
    assert result is vectors
