"""Integration tests for useGraph() functionality."""

import pytest
import time

from gqldb.config import ConfigBuilder
from gqldb.client import GqldbClient
from tests.conftest import TEST_HOST, TEST_USERNAME, TEST_PASSWORD, TEST_DATABASE


class TestUseGraphIntegration:
    """Integration tests for useGraph functionality."""

    @pytest.fixture
    def client(self):
        """Create a test client."""
        config = (
            ConfigBuilder()
            .hosts(TEST_HOST)
            .username(TEST_USERNAME)
            .password(TEST_PASSWORD)
            .default_graph(TEST_DATABASE)
            .timeout(30)
            .build()
        )
        client = GqldbClient(config)
        try:
            client.login(TEST_USERNAME, TEST_PASSWORD)
        except Exception as e:
            if "authentication is not enabled" in str(e).lower():
                pass  # Continue without login
            else:
                raise
        yield client
        try:
            if client.is_logged_in():
                client.logout()
        except Exception:
            pass
        client.close()

    def test_usegraph_changes_default_graph(self, client):
        """useGraph should change the default graph for queries."""
        # Use a known graph
        client.use_graph(TEST_DATABASE)

        # Execute query - should use the graph set by useGraph
        response = client.gql("MATCH (n) RETURN n LIMIT 1")

        assert response is not None
        print(f"useGraph test passed, rows returned: {response.row_count}")

    def test_usegraph_with_nonexistent_graph_error(self, client):
        """useGraph with non-existent graph should cause error."""
        fake_graph = f"non_existent_graph_{int(time.time())}"

        with pytest.raises(Exception) as exc_info:
            client.use_graph(fake_graph)

        error_msg = str(exc_info.value).lower()
        assert "not found" in error_msg or "does not exist" in error_msg or "invalid" in error_msg
        print(f"Got expected error for non-existent graph: {exc_info.value}")

    def test_query_config_overrides_usegraph(self, client):
        """Explicit graphName in QueryConfig should override useGraph."""
        from gqldb.client import QueryConfig

        # Set default graph via useGraph
        client.use_graph(TEST_DATABASE)

        # Query with different graph in config (non-existent)
        fake_graph = f"override_test_graph_{int(time.time())}"

        with pytest.raises(Exception) as exc_info:
            client.gql("MATCH (n) RETURN n LIMIT 1", QueryConfig(graph_name=fake_graph))

        error_msg = str(exc_info.value).lower()
        assert "not found" in error_msg or "does not exist" in error_msg or "invalid" in error_msg
        print(f"QueryConfig.graph_name correctly overrides useGraph: {exc_info.value}")

    def test_usegraph_persists_across_queries(self, client):
        """useGraph should persist across multiple queries."""
        client.use_graph(TEST_DATABASE)

        # Execute multiple queries
        for i in range(3):
            response = client.gql("MATCH (n) RETURN n LIMIT 1")
            assert response is not None

        print("useGraph persisted across 3 queries")

    def test_usegraph_overrides_config_default_graph(self):
        """useGraph should override config.default_graph."""
        # Create a new client with no default graph in config
        config = (
            ConfigBuilder()
            .hosts(TEST_HOST)
            .username(TEST_USERNAME)
            .password(TEST_PASSWORD)
            .default_graph("")  # No default graph
            .timeout(30)
            .build()
        )

        test_client = GqldbClient(config)

        try:
            try:
                test_client.login(TEST_USERNAME, TEST_PASSWORD)
            except Exception as e:
                if "authentication is not enabled" not in str(e).lower():
                    raise

            # Use a valid graph via useGraph
            test_client.use_graph(TEST_DATABASE)

            # Query should succeed because useGraph sets session.default_graph
            response = test_client.gql("MATCH (n) RETURN n LIMIT 1")
            assert response is not None
            print("useGraph successfully set session.default_graph")
        finally:
            test_client.close()

    def test_usegraph_empty_string_rejected(self, client):
        """useGraph with empty string should be rejected by server."""
        with pytest.raises(Exception) as exc_info:
            client.use_graph("")

        error_msg = str(exc_info.value).lower()
        assert "required" in error_msg or "invalid" in error_msg or "empty" in error_msg
        print(f"Server correctly rejected empty graph name: {exc_info.value}")

    def test_multiple_usegraph_uses_latest(self, client):
        """Multiple useGraph calls should use the latest value."""
        # First useGraph with valid graph
        client.use_graph(TEST_DATABASE)

        # Second useGraph with same graph
        client.use_graph(TEST_DATABASE)

        # Query should succeed
        response = client.gql("MATCH (n) RETURN n LIMIT 1")
        assert response is not None
        print("Latest useGraph value is correctly used")

    def test_usegraph_with_gql_stream(self, client):
        """useGraph should work with gql_stream."""
        client.use_graph(TEST_DATABASE)

        responses = []
        client.gql_stream("MATCH (n) RETURN n LIMIT 5", callback=lambda r: responses.append(r))

        assert len(responses) > 0
        print(f"gql_stream received {len(responses)} responses with useGraph")
