from atomsql.orm.models import Model
from atomsql.orm.fields import StringField, IntegerField


# Define a test model
class User(Model):
    name = StringField()
    age = IntegerField()


def test_queryset_filter_sql_generation(db):
    """
    Verifies that BinaryExpression objects are correctly converted into
    qualified SQL conditions within the WHERE clause.
    """
    db.register(User)  # Register model to associate with the DB backend

    # Combine BinaryExpression (User.age > 18) with traditional kwarg (name="Alice")
    qs = User.objects().filter(User.age > 18, name="Alice")
    sql, params = qs._build_sql()

    # Check for qualified column names to prevent ambiguity during joins
    assert '"user"."age" >' in sql
    assert '"name" =' in sql  # kwarg filters aren't qualified currently
    assert 18 in params
    assert "Alice" in params


def test_binary_expression_execution(db):
    """
    Functional test to ensure that User.age > 18 correctly filters
    records in a live SQLite database.
    """
    db.register(User)

    # Setup test data
    User(name="Alice", age=25).save()
    User(name="Bob", age=15).save()
    User(name="Charlie", age=18).save()

    # Filter using BinaryExpression
    results = list(User.objects().filter(User.age > 18))

    assert len(results) == 1
    assert results[0].name == "Alice"


def test_all_operator_overloads(db):
    """
    Tests all implemented operator overloads: <, <=, >, >=, !=, ==.
    """
    db.register(User)
    User(name="Tester", age=20).save()

    # Test each operator defined in fields.py
    assert User.objects().filter(User.age < 21).count() == 1
    assert User.objects().filter(User.age <= 20).count() == 1
    assert User.objects().filter(User.age > 19).count() == 1
    assert User.objects().filter(User.age >= 20).count() == 1
    assert User.objects().filter(User.age != 10).count() == 1
    assert User.objects().filter(User.age == 20).count() == 1


def test_chained_binary_filters(db):
    """
    Ensures that multiple .filter() calls correctly append expressions
    to the QuerySet's internal state.
    """
    db.register(User)
    User(name="Alice", age=30).save()
    User(name="Alice", age=20).save()

    # Chain filters
    qs = User.objects().filter(name="Alice").filter(User.age > 25)
    results = list(qs)

    assert len(results) == 1
    assert results[0].age == 30


def test_binary_expression_with_joins(db):
    """
    Verifies that BinaryExpressions work correctly when using select_related.
    This relies on the qualified table names in the SQL builder.
    """
    from atomsql.orm.fields import ForeignKey

    class Post(Model):
        title = StringField()
        author = ForeignKey(User, related_name="posts")

    db.register(User)
    db.register(Post)

    u = User(name="Author", age=40)
    u.save()
    Post(title="AtomSQL Tips", author=u).save()

    # Filter on a joined table's field using BinaryExpression
    qs = Post.objects().select_related("author").filter(User.age > 30)
    results = list(qs)

    assert len(results) == 1
    assert results[0].author.name == "Author"
