"""Test automatic type inference for comparison operators (EFD-125)."""

from __future__ import annotations

import pytest

from crystflux.v1 import Crystallizer, it


# ============================================================================
# Category 1: Basic Type Inference Tests (4 tests)
# ============================================================================

def test_auto_infer_int_from_int_literal() -> None:
    """Infer int type from int literal."""
    data = [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": 18},
        {"name": "Charlie", "age": 25}
    ]
    users = Crystallizer.latent(data).to_array()
    adults = users.filter(it.age > 21)
    names = adults.map(it.name).as_str_array()
    assert names == ("Alice", "Charlie")


def test_auto_infer_float_from_float_literal() -> None:
    """Infer float type from float literal."""
    data = [
        {"name": "Alice", "score": 85.5},
        {"name": "Bob", "score": 70.0},
        {"name": "Charlie", "score": 92.0}
    ]
    results = Crystallizer.latent(data).filter(it.score > 85.0)
    names = results.map(it.name).as_str_array()
    assert names == ("Alice", "Charlie")


def test_auto_infer_bool_from_bool_literal() -> None:
    """Infer bool type from bool literal."""
    data = [
        {"name": "Alice", "active": True},
        {"name": "Bob", "active": False},
        {"name": "Charlie", "active": True}
    ]
    # Testing bool literal type inference, requires explicit comparison
    active = Crystallizer.latent(data).filter(it.active == True)  # noqa: E712
    names = active.map(it.name).as_str_array()
    assert names == ("Alice", "Charlie")


def test_auto_infer_none_as_int() -> None:
    """Infer int type from None (default behavior)."""
    data = [
        {"name": "Alice", "count": 5},
        {"name": "Bob", "count": None},
        {"name": "Charlie", "count": 0}
    ]
    users = Crystallizer.latent(data).to_array()
    # None > 0 evaluates to False
    result = users.filter(it.count > 0)
    names = result.map(it.name).as_str_array()
    assert names == ("Alice",)


# ============================================================================
# Category 2: All Comparison Operators Test (1 test)
# ============================================================================

def test_comparison_with_all_operators() -> None:
    """Verify all 6 comparison operators work correctly."""
    data = [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": 18},
        {"name": "Charlie", "age": 25}
    ]
    users = Crystallizer.latent(data).to_array()

    # gt
    assert users.filter(it.age > 25).map(it.name).as_str_array() == ("Alice",)  # 30
    # ge
    assert users.filter(it.age >= 25).map(it.name).as_str_array() == ("Alice", "Charlie")  # 30, 25
    # lt
    assert users.filter(it.age < 25).map(it.name).as_str_array() == ("Bob",)  # 18
    # le
    assert users.filter(it.age <= 25).map(it.name).as_str_array() == ("Bob", "Charlie")  # 18, 25
    # eq
    assert users.filter(it.age == 25).map(it.name).as_str_array() == ("Charlie",)  # 25
    # ne
    assert users.filter(it.age != 25).map(it.name).as_str_array() == ("Alice", "Bob")  # 30, 18


# ============================================================================
# Category 3: Edge Case Tests (2 tests)
# ============================================================================

def test_none_value_inference() -> None:
    """Comparison with fields containing None values."""
    data = [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": None},
        {"name": "Charlie", "age": 18}
    ]
    users = Crystallizer.latent(data).to_array()
    # None > 21 evaluates to False (as_int returns None)
    adults = users.filter(it.age > 21)
    names = adults.map(it.name).as_str_array()
    assert names == ("Alice",)


def test_error_on_unsupported_type() -> None:
    """Verify TypeError is raised for values that cannot be type-inferred."""
    with pytest.raises(TypeError, match="Cannot infer scalar type"):
        # TypeError raised during comparison operator evaluation
        _ = it.name > "Alice"  # Strings cannot be inferred


# ============================================================================
# Category 4: Backward Compatibility Tests (3 tests)
# ============================================================================

def test_as_int_still_works() -> None:
    """Verify explicit .as_int() still works."""
    data = [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": 18},
        {"name": "Charlie", "age": 25}
    ]
    users = Crystallizer.latent(data).to_array()
    adults = users.filter(it.age.as_int() > 21)
    names = adults.map(it.name).as_str_array()
    assert names == ("Alice", "Charlie")


def test_as_float_still_works() -> None:
    """Verify explicit .as_float() still works."""
    data = [
        {"name": "Alice", "score": 85.5},
        {"name": "Bob", "score": 70.0},
        {"name": "Charlie", "score": 92.0}
    ]
    users = Crystallizer.latent(data).to_array()
    filtered = users.filter(it.score.as_float() > 80.0)
    names = filtered.map(it.name).as_str_array()
    assert names == ("Alice", "Charlie")


def test_old_and_new_syntax_equivalence() -> None:
    """Verify old and new syntax are equivalent."""
    data = [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": 18},
        {"name": "Charlie", "age": 25}
    ]
    users = Crystallizer.latent(data).to_array()

    old_syntax = users.filter(it.age.as_int() > 21)
    new_syntax = users.filter(it.age > 21)
    old_names = old_syntax.map(it.name).as_str_array()
    new_names = new_syntax.map(it.name).as_str_array()

    assert old_names == new_names == ("Alice", "Charlie")
