"""Tests for automatic normalization of compound expressions."""

from therismos import AllExpr, AnyExpr, F


class TestAllExprNormalization:
    """Test automatic flattening of nested AllExpr."""

    def test_simple_all_expr(self) -> None:
        """Test simple AllExpr without nesting."""
        age = F("age")
        name = F("name")
        expr = AllExpr(age > 18, name == "Alice")
        assert len(expr.exprs) == 2

    def test_nested_all_expr_flattening(self) -> None:
        """Test that nested AllExpr is flattened."""
        age = F("age")
        name = F("name")
        status = F("status")

        inner = AllExpr(age > 18, name == "Alice")
        outer = AllExpr(inner, status == "active")

        # Should flatten to 3 expressions
        assert len(outer.exprs) == 3
        assert outer.exprs[0] == age > 18
        assert outer.exprs[1] == name == "Alice"
        assert outer.exprs[2] == status == "active"

    def test_multiple_nested_all_expr(self) -> None:
        """Test flattening of multiple nested AllExpr."""
        a = F("a")
        b = F("b")
        c = F("c")
        d = F("d")

        expr1 = AllExpr(a == 1, b == 2)
        expr2 = AllExpr(c == 3, d == 4)
        expr3 = AllExpr(expr1, expr2)

        # Should flatten to 4 expressions
        assert len(expr3.exprs) == 4

    def test_deeply_nested_all_expr(self) -> None:
        """Test deeply nested AllExpr flattening."""
        fields = [F(f"f{i}") for i in range(5)]

        # Create: AllExpr(AllExpr(AllExpr(f0, f1), f2), AllExpr(f3, f4))
        inner1 = AllExpr(fields[0] == 0, fields[1] == 1)
        inner2 = AllExpr(inner1, fields[2] == 2)
        inner3 = AllExpr(fields[3] == 3, fields[4] == 4)
        outer = AllExpr(inner2, inner3)

        # Should flatten completely
        assert len(outer.exprs) == 5

    def test_and_operator_flattening(self) -> None:
        """Test that & operator also results in flattening."""
        a = F("a")
        b = F("b")
        c = F("c")

        # (a == 1) & (b == 2) & (c == 3)
        expr = (a == 1) & (b == 2) & (c == 3)
        assert isinstance(expr, AllExpr)
        assert len(expr.exprs) == 3


class TestAnyExprNormalization:
    """Test automatic flattening of nested AnyExpr."""

    def test_simple_any_expr(self) -> None:
        """Test simple AnyExpr without nesting."""
        status = F("status")
        expr = AnyExpr(status == "active", status == "pending")
        assert len(expr.exprs) == 2

    def test_nested_any_expr_flattening(self) -> None:
        """Test that nested AnyExpr is flattened."""
        status = F("status")
        role = F("role")

        inner = AnyExpr(status == "active", status == "pending")
        outer = AnyExpr(inner, role == "admin")

        # Should flatten to 3 expressions
        assert len(outer.exprs) == 3
        assert outer.exprs[0] == status == "active"
        assert outer.exprs[1] == status == "pending"
        assert outer.exprs[2] == role == "admin"

    def test_multiple_nested_any_expr(self) -> None:
        """Test flattening of multiple nested AnyExpr."""
        a = F("a")
        b = F("b")
        c = F("c")
        d = F("d")

        expr1 = AnyExpr(a == 1, b == 2)
        expr2 = AnyExpr(c == 3, d == 4)
        expr3 = AnyExpr(expr1, expr2)

        # Should flatten to 4 expressions
        assert len(expr3.exprs) == 4

    def test_deeply_nested_any_expr(self) -> None:
        """Test deeply nested AnyExpr flattening."""
        fields = [F(f"f{i}") for i in range(5)]

        inner1 = AnyExpr(fields[0] == 0, fields[1] == 1)
        inner2 = AnyExpr(inner1, fields[2] == 2)
        inner3 = AnyExpr(fields[3] == 3, fields[4] == 4)
        outer = AnyExpr(inner2, inner3)

        # Should flatten completely
        assert len(outer.exprs) == 5

    def test_or_operator_flattening(self) -> None:
        """Test that | operator also results in flattening."""
        status = F("status")

        # status == "a" | status == "b" | status == "c"
        expr = (status == "a") | (status == "b") | (status == "c")
        assert isinstance(expr, AnyExpr)
        assert len(expr.exprs) == 3


class TestMixedNormalization:
    """Test that mixed AllExpr/AnyExpr don't flatten across boundaries."""

    def test_all_inside_any_not_flattened(self) -> None:
        """Test that AllExpr inside AnyExpr is not flattened."""
        a = F("a")
        b = F("b")
        c = F("c")

        inner = AllExpr(a == 1, b == 2)
        outer = AnyExpr(inner, c == 3)

        # Should have 2 expressions: the AllExpr and c == 3
        assert len(outer.exprs) == 2
        assert isinstance(outer.exprs[0], AllExpr)

    def test_any_inside_all_not_flattened(self) -> None:
        """Test that AnyExpr inside AllExpr is not flattened."""
        a = F("a")
        b = F("b")
        c = F("c")

        inner = AnyExpr(a == 1, b == 2)
        outer = AllExpr(inner, c == 3)

        # Should have 2 expressions: the AnyExpr and c == 3
        assert len(outer.exprs) == 2
        assert isinstance(outer.exprs[0], AnyExpr)

    def test_complex_mixed_expression(self) -> None:
        """Test complex mixed AND/OR expression."""
        a = F("a")
        b = F("b")
        c = F("c")
        d = F("d")

        # ((a == 1) | (b == 2)) & ((c == 3) | (d == 4))
        expr = ((a == 1) | (b == 2)) & ((c == 3) | (d == 4))

        assert isinstance(expr, AllExpr)
        assert len(expr.exprs) == 2
        assert isinstance(expr.exprs[0], AnyExpr)
        assert isinstance(expr.exprs[1], AnyExpr)


class TestEmptyAndSingleExpressions:
    """Test normalization of empty and single-element compound expressions."""

    def test_empty_all_expr(self) -> None:
        """Test AllExpr with no operands."""
        expr = AllExpr()
        assert len(expr.exprs) == 0

    def test_single_all_expr(self) -> None:
        """Test AllExpr with single operand (not optimized at this level)."""
        age = F("age")
        expr = AllExpr(age > 18)
        assert len(expr.exprs) == 1

    def test_empty_any_expr(self) -> None:
        """Test AnyExpr with no operands."""
        expr = AnyExpr()
        assert len(expr.exprs) == 0

    def test_single_any_expr(self) -> None:
        """Test AnyExpr with single operand (not optimized at this level)."""
        age = F("age")
        expr = AnyExpr(age > 18)
        assert len(expr.exprs) == 1
