import pytest
import sys
from pathlib import Path

# Add parent of db_core to path
parent_dir = Path(__file__).parent.parent.parent
if str(parent_dir) not in sys.path:
    sys.path.insert(0, str(parent_dir))

from db_core.clients.postgresql import PostgresClient

pytestmark = pytest.mark.pg


@pytest.mark.asyncio
async def test_to_sql_basic(db_client: PostgresClient):
    """Test to_sql() method returns SQL string"""
    sql = db_client.table("users").to_sql()
    
    assert isinstance(sql, str)
    assert "SELECT" in sql.upper()
    assert "users" in sql


@pytest.mark.asyncio
async def test_to_sql_with_where(db_client: PostgresClient):
    """Test to_sql() with WHERE clause"""
    sql = db_client.table("users").where("age", ">", 25).to_sql()
    
    assert "WHERE" in sql.upper() or "where" in sql
    assert "age" in sql
    assert "25" in sql


@pytest.mark.asyncio
async def test_to_sql_complex_query(db_client: PostgresClient):
    """Test to_sql() with complex query"""
    sql = (
        db_client.table("users")
        .select("name", "email")
        .where("age", ">=", 18)
        .where_like("email", "%@example.com")
        .order_by("-age")
        .limit(10)
        .to_sql()
    )
    
    assert "SELECT" in sql.upper()
    assert "name" in sql
    assert "email" in sql
    assert "WHERE" in sql.upper() or "where" in sql
    assert "ORDER BY" in sql.upper() or "order by" in sql.lower()
    assert "LIMIT" in sql.upper() or "limit" in sql.lower()
    assert "10" in sql


@pytest.mark.asyncio
async def test_to_sql_with_or(db_client: PostgresClient):
    """Test to_sql() with OR conditions"""
    sql = (
        db_client.table("users")
        .where("age", 25)
        .or_where("age", 30)
        .to_sql()
    )
    
    assert "SELECT" in sql.upper()
    assert "users" in sql
    assert "25" in sql
    assert "30" in sql


@pytest.mark.asyncio
async def test_to_sql_with_group(db_client: PostgresClient):
    """Test to_sql() with grouped conditions"""
    sql = (
        db_client.table("users")
        .where("age", ">", 25)
        .where_group(lambda q: q.where("name", "Alice").or_where("name", "Bob"))
        .to_sql()
    )
    
    assert "SELECT" in sql.upper()
    assert "users" in sql
    assert "Alice" in sql
    assert "Bob" in sql


@pytest.mark.asyncio
async def test_to_sql_with_or_group(db_client: PostgresClient):
    """Test to_sql() with OR grouped conditions"""
    sql = (
        db_client.table("posts")
        .where("published", True)
        .or_where_group(lambda q: q.where("views", 0).where("title", "Draft Post"))
        .to_sql()
    )

    assert "SELECT" in sql.upper()
    assert "posts" in sql
    assert "Draft Post" in sql
    assert "OR" in sql.upper()


@pytest.mark.asyncio
async def test_to_sql_with_nested_groups(db_client: PostgresClient):
    """Test to_sql() with nested grouped conditions"""
    sql = (
        db_client.table("posts")
        .where_group(lambda q:
            q.where("published", True)
             .where_group(lambda q2: q2.where_gte("views", 100).or_where("title", "Bob's Post"))
        )
        .or_where("title", "Draft Post")
        .to_sql()
    )

    assert "SELECT" in sql.upper()
    assert "posts" in sql
    assert "Draft Post" in sql
    assert "Bob''s Post" in sql
    assert "OR" in sql.upper()


@pytest.mark.asyncio
async def test_debug_query(db_client: PostgresClient):
    """Test debug_query() method"""
    qb = db_client.table("users").where("age", ">", 18)
    debug_str = db_client.debug_query(qb.query)
    
    assert isinstance(debug_str, str)
    assert "SQL:" in debug_str
    assert "SELECT" in debug_str.upper()
    assert "users" in debug_str


@pytest.mark.asyncio
async def test_raw_query_returns_tuple(db_client: PostgresClient):
    """Test raw_query() returns (sql, params) tuple"""
    qb = db_client.table("users").where("id", 1)
    sql, params = db_client.raw_query(qb.query)
    
    assert isinstance(sql, str)
    assert isinstance(params, dict)
    assert "SELECT" in sql.upper()


@pytest.mark.asyncio
async def test_to_sql_does_not_execute(db_client: PostgresClient):
    """Test that to_sql() doesn't execute the query"""
    # This should not raise an error even with invalid table
    sql = db_client.table("nonexistent_table").to_sql()
    
    assert isinstance(sql, str)
    assert "nonexistent_table" in sql


@pytest.mark.asyncio
async def test_sql_preview_workflow(db_client: PostgresClient):
    """Test workflow: preview SQL, then execute"""
    qb = db_client.table("users").where("age", ">", 25)
    
    # Preview the SQL
    sql = qb.to_sql()
    assert "SELECT" in sql.upper()
    assert "users" in sql
    
    # Now execute it
    result = await qb.get()
    assert result.count() >= 0  # Should execute successfully


@pytest.mark.asyncio
async def test_debug_query_with_complex_conditions(db_client: PostgresClient):
    """Test debug_query() with complex conditions"""
    qb = (
        db_client.table("posts")
        .where("published", True)
        .where_in("user_id", [1, 2, 3])
        .order_by("-views")
    )
    
    debug_str = db_client.debug_query(qb.query)
    
    assert "SQL:" in debug_str
    assert "posts" in debug_str
    assert "published" in debug_str or "TRUE" in debug_str.upper()
