"""Integration tests for PiggieDriver.

These tests require a running PostgreSQL instance with AGE and pgvector.
Run with: pytest -m integration
"""

import pytest

pytestmark = pytest.mark.integration


def test_connect_and_repr(db):
    assert "connected" in repr(db)
    assert db.graph is not None


def test_create_and_query_nodes(fresh_graph):
    db = fresh_graph
    db.cypher("CREATE (:Person {name: 'Alice', age: 30})")
    db.commit()
    db.cypher("CREATE (:Person {name: 'Bob', age: 25})")
    db.commit()

    result = db.cypher(
        "MATCH (n:Person) RETURN n.name, n.age ORDER BY n.name"
    )
    assert len(result) == 2
    dicts = result.to_dicts()
    assert dicts[0]["name"] == "Alice"
    assert dicts[1]["name"] == "Bob"


def test_query_to_dataframe(fresh_graph):
    db = fresh_graph
    db.cypher("CREATE (:Person {name: 'Alice', age: 30})")
    db.commit()

    result = db.cypher("MATCH (n:Person) RETURN n.name AS name, n.age AS age")
    df = result.to_df()
    assert list(df.columns) == ["name", "age"]
    assert len(df) == 1
    assert df["name"].iloc[0] == "Alice"


def test_query_with_params(fresh_graph):
    db = fresh_graph
    db.cypher("CREATE (:Person {name: 'Alice', age: 30})")
    db.cypher("CREATE (:Person {name: 'Bob', age: 25})")
    db.commit()

    result = db.cypher(
        "MATCH (n:Person) WHERE n.age > %s RETURN n.name",
        params=(27,),
    )
    assert len(result) == 1
    assert result.single()["name"] == "Alice"


def test_create_edge_and_query(fresh_graph):
    db = fresh_graph
    db.cypher("CREATE (:Person {name: 'Alice'})")
    db.cypher("CREATE (:Person {name: 'Bob'})")
    db.commit()

    db.cypher(
        "MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'}) "
        "CREATE (a)-[:KNOWS {since: 2020}]->(b)"
    )
    db.commit()

    result = db.cypher(
        "MATCH (a:Person)-[r:KNOWS]->(b:Person) "
        "RETURN a.name AS source, b.name AS target, r.since AS since"
    )
    rec = result.single()
    assert rec["source"] == "Alice"
    assert rec["target"] == "Bob"
    assert rec["since"] == 2020


def test_return_full_vertex(fresh_graph):
    db = fresh_graph
    db.cypher("CREATE (:Person {name: 'Alice', age: 30})")
    db.commit()

    result = db.cypher("MATCH (n:Person) RETURN n")
    rec = result.single()
    node = rec["n"]
    from piggie.types import Vertex
    assert isinstance(node, Vertex)
    assert node["name"] == "Alice"
    assert node.label == "Person"


def test_expand_vertex_in_dataframe(fresh_graph):
    db = fresh_graph
    db.cypher("CREATE (:Person {name: 'Alice', age: 30})")
    db.commit()

    result = db.cypher("MATCH (n:Person) RETURN n")
    df = result.to_df(expand=True)
    assert "n.name" in df.columns
    assert df["n.name"].iloc[0] == "Alice"


def test_sql_query(db):
    result = db.sql("SELECT 1 AS val")
    assert result.single()["val"] == 1


def test_list_graphs(db):
    graphs = db.list_graphs()
    assert isinstance(graphs, list)


def test_schema_introspection(fresh_graph):
    db = fresh_graph
    db.cypher("CREATE (:Person {name: 'Alice'})")
    db.commit()

    schema = db.get_schema()
    assert schema["graph"] == db.graph
    assert isinstance(schema["vertex_labels"], list)
    assert isinstance(schema["edge_labels"], list)
    assert isinstance(schema["vector_indexes"], list)


def test_transaction_commit(fresh_graph):
    db = fresh_graph
    with db.transaction():
        db.cypher("CREATE (:Person {name: 'Alice'})")
        db.cypher("CREATE (:Person {name: 'Bob'})")
    # Should be committed
    result = db.cypher("MATCH (n:Person) RETURN count(n) AS cnt")
    assert result.single()["cnt"] == 2


def test_transaction_rollback(fresh_graph):
    db = fresh_graph
    db.cypher("CREATE (:Person {name: 'Existing'})")
    db.commit()

    try:
        with db.transaction():
            db.cypher("CREATE (:Person {name: 'Temp'})")
            raise ValueError("intentional error")
    except ValueError:
        pass

    # Only the pre-existing node should be there
    result = db.cypher("MATCH (n:Person) RETURN count(n) AS cnt")
    assert result.single()["cnt"] == 1


def test_context_manager():
    import os

    import piggie
    dsn = os.environ.get(
        "PIGGIE_TEST_DSN",
        "host=/var/run/postgresql port=5433 dbname=piggie user=gregf",
    )
    with piggie.connect(dsn) as db:
        result = db.sql("SELECT 1 AS val")
        assert result.single()["val"] == 1
    assert db.connection.closed


def test_pool_basic():
    import os

    import piggie
    dsn = os.environ.get(
        "PIGGIE_TEST_DSN",
        "host=/var/run/postgresql port=5433 dbname=piggie user=gregf",
    )
    pool = piggie.connect_pool(dsn, min_size=1, max_size=2)
    with pool.connection() as db:
        result = db.sql("SELECT 1 AS val")
        assert result.single()["val"] == 1
    pool.close()
