import pytest
import sys
import uuid
from pathlib import 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.doris import DorisClient
from db_core.query import Query

pytestmark = pytest.mark.doris


@pytest.mark.asyncio
async def test_connection(doris_client: DorisClient):
    assert doris_client.engine is not None
    assert doris_client.session_maker is not None


@pytest.mark.asyncio
async def test_disconnect(doris_client: DorisClient):
    result = await doris_client.table("users").limit(1).get()
    assert result.count() == 1


@pytest.mark.asyncio
async def test_raw_query(doris_client: DorisClient):
    query = Query(table="users", selects=["name", "email"])
    sql, params = doris_client.raw_query(query)

    assert "SELECT" in sql.upper()
    assert "users" in sql
    assert "name" in sql
    assert "email" in sql


@pytest.mark.asyncio
async def test_raw_query_with_where(doris_client: DorisClient):
    qb = doris_client.table("users").where("age", ">", 25)
    sql, params = doris_client.raw_query(qb.query)

    assert "WHERE" in sql.upper() or "where" in sql
    assert "age" in sql


@pytest.mark.asyncio
async def test_explain(doris_client: DorisClient):
    query = Query(table="users")
    explain_output = await doris_client.explain(query)

    assert explain_output is not None
    assert len(explain_output) > 0


@pytest.mark.asyncio
async def test_table_method(doris_client: DorisClient):
    qb = doris_client.table("users")
    assert qb is not None
    assert qb.query.table == "users"
    assert hasattr(qb, "where")
    assert hasattr(qb, "select")
    assert hasattr(qb, "get")


@pytest.mark.asyncio
async def test_execute_simple_query(doris_client: DorisClient):
    query = Query(table="users", selects=["*"])
    result = await doris_client._execute(query)

    assert result is not None
    assert result.count() == 4


@pytest.mark.asyncio
async def test_execute_query_with_limit(doris_client: DorisClient):
    query = Query(table="users", selects=["*"], limit=2)
    result = await doris_client._execute(query)

    assert result.count() == 2


@pytest.mark.asyncio
async def test_find_one_and_find_many(doris_client: DorisClient):
    alice = await doris_client.find_one("users", {"email": "alice@example.com"})
    assert alice is not None
    assert alice["name"] == "Alice Smith"
    assert alice["age"] == 30

    missing = await doris_client.find_one("users", {"email": "missing@example.com"})
    assert missing is None

    users = await doris_client.find_many("users", {"age": 25})
    assert isinstance(users, list)
    assert len(users) == 1
    assert users[0]["name"] == "Bob Jones"

    top_two = await doris_client.find_many("users", limit=2, order_by=["-age"])
    assert len(top_two) == 2
    assert top_two[0]["age"] >= top_two[1]["age"]


@pytest.mark.asyncio
async def test_create_method_inserts_new_user(doris_client: DorisClient):
    unique_email = f"eve.save.{uuid.uuid4().hex}@example.com"
    new_user = {
        "name": "Eve Adams",
        "email": unique_email,
        "age": 22,
    }

    created = await doris_client.create("users", new_user, returning=["id", "name", "email", "age"])
    assert created is not None
    assert created["email"] == unique_email
    assert created["name"] == "Eve Adams"
    assert created["age"] == 22

    fetched = await doris_client.find_by_id("users", created["id"])
    assert fetched is not None
    assert fetched["email"] == unique_email

    deleted = await doris_client.delete_by_id("users", created["id"])
    assert deleted == 1


@pytest.mark.asyncio
async def test_save_method_updates_existing_user(doris_client: DorisClient):
    unique_email = f"frank.save.{uuid.uuid4().hex}@example.com"
    created = await doris_client.create(
        "users",
        {"name": "Frank Miller", "email": unique_email, "age": 29},
        returning=["id", "email", "age"]
    )
    assert created is not None

    updated = await doris_client.save(
        "users",
        {"id": created["id"], "name": "Frank M.", "age": 30}
    )
    assert updated is not None
    assert updated["id"] == created["id"]
    assert updated["name"] == "Frank M."
    assert updated["age"] == 30

    deleted = await doris_client.delete_by_id("users", created["id"])
    assert deleted == 1


@pytest.mark.asyncio
async def test_pool_settings(doris_client: DorisClient):
    assert doris_client.engine.pool.size() >= 0


@pytest.mark.asyncio
async def test_find_all_method(doris_client: DorisClient):
    users = await doris_client.find_all("users", limit=2)
    assert len(users) == 2


@pytest.mark.asyncio
async def test_bulk_update(doris_client: DorisClient):
    users = await doris_client.find_all("users", limit=2)
    ids = [u["id"] for u in users]

    updated = await doris_client.bulk_update("users", ids, {"age": 99})
    assert updated == 2

    for uid in ids:
        u = await doris_client.find_by_id("users", uid)
        assert u["age"] == 99

    await doris_client.bulk_update("users", ids, {"age": users[0].get("_orig_age", 30)})


@pytest.mark.asyncio
async def test_bulk_delete(doris_client: DorisClient):
    unique_email = f"bulk.del.{uuid.uuid4().hex}@example.com"
    created = await doris_client.create(
        "users",
        {"name": "Bulk Del", "email": unique_email, "age": 1},
        returning=["id"]
    )
    assert created is not None

    deleted = await doris_client.bulk_delete("users", [created["id"]])
    assert deleted == 1

    fetched = await doris_client.find_by_id("users", created["id"])
    assert fetched is None
