"""Transaction Service integration tests."""

import pytest
import uuid

from gqldb.client import GqldbClient
from gqldb.config import GqldbConfig
from gqldb.types import GraphType
from tests.conftest import check_auth_enabled, drop_test_graph, TEST_USERNAME, TEST_PASSWORD


@pytest.mark.integration
class TestTransaction:
    """Tests for transaction service.

    Note: Transaction operations require a valid session, which means
    authentication must be enabled on the server.
    """

    @pytest.fixture
    def logged_in_client(self, test_config: GqldbConfig):
        """Return a logged-in client, skip if auth disabled."""
        client = GqldbClient(test_config)
        if not check_auth_enabled(client):
            client.close()
            pytest.skip("Transaction service requires authentication to be enabled")
        client.login(TEST_USERNAME, TEST_PASSWORD)
        yield client
        try:
            client.logout()
        except Exception:
            pass
        client.close()

    @pytest.fixture
    def tx_test_graph(self, logged_in_client: GqldbClient, request):
        """Create a temporary test graph for transaction tests."""
        graph_name = f"tx_test_{uuid.uuid4().hex[:8]}"
        logged_in_client.create_graph(graph_name, GraphType.OPEN, "Transaction test graph")
        yield graph_name
        drop_test_graph(logged_in_client, graph_name)

    def test_begin_and_commit_transaction(self, logged_in_client: GqldbClient, tx_test_graph: str):
        """Test beginning and committing a transaction."""
        # Begin transaction
        tx = logged_in_client.begin_transaction(tx_test_graph, read_only=False)
        assert tx is not None
        assert tx.id > 0
        print(f"Started transaction: id={tx.id}, graph={tx.graph_name}")

        # Commit transaction
        success = logged_in_client.commit(tx.id)
        assert success
        print("Transaction committed successfully")

    def test_begin_and_rollback_transaction(self, logged_in_client: GqldbClient, tx_test_graph: str):
        """Test beginning and rolling back a transaction."""
        # Begin transaction
        tx = logged_in_client.begin_transaction(tx_test_graph, read_only=False)
        assert tx is not None
        assert tx.id > 0
        print(f"Started transaction: id={tx.id}")

        # Rollback transaction
        success = logged_in_client.rollback(tx.id)
        assert success
        print("Transaction rolled back successfully")

    def test_read_only_transaction(self, logged_in_client: GqldbClient, tx_test_graph: str):
        """Test read-only transaction."""
        # Begin read-only transaction
        tx = logged_in_client.begin_transaction(tx_test_graph, read_only=True)
        assert tx is not None
        assert tx.id > 0
        assert tx.read_only
        print(f"Started read-only transaction: id={tx.id}")

        # Commit (or rollback) the read-only transaction
        success = logged_in_client.commit(tx.id)
        assert success
        print("Read-only transaction committed successfully")

    def test_list_transactions(self, logged_in_client: GqldbClient, tx_test_graph: str):
        """Test listing active transactions."""
        # Begin a transaction
        tx = logged_in_client.begin_transaction(tx_test_graph, read_only=False)
        assert tx is not None

        try:
            # List transactions
            transactions = logged_in_client.list_transactions()
            assert isinstance(transactions, list)
            print(f"Found {len(transactions)} active transactions")
            for t in transactions:
                print(f"  - id={t.transaction_id}, graph={t.graph_name}, read_only={t.read_only}")
        finally:
            # Clean up - rollback the transaction
            logged_in_client.rollback(tx.id)

    def test_with_transaction_commit(self, logged_in_client: GqldbClient, tx_test_graph: str):
        """Test with_transaction helper for auto-commit."""
        executed = []

        def tx_func(tx_id: int):
            assert tx_id > 0
            executed.append(tx_id)
            print(f"Executing in transaction {tx_id}")

        logged_in_client.with_transaction(tx_test_graph, tx_func)
        assert len(executed) == 1
        print("with_transaction completed successfully (committed)")

    def test_with_transaction_rollback_on_error(self, logged_in_client: GqldbClient, tx_test_graph: str):
        """Test with_transaction helper for auto-rollback on error."""

        def tx_func(tx_id: int):
            print(f"Executing in transaction {tx_id}")
            raise ValueError("Simulated error")

        with pytest.raises(ValueError) as exc_info:
            logged_in_client.with_transaction(tx_test_graph, tx_func)
        assert "Simulated error" in str(exc_info.value)
        print("with_transaction rolled back on error as expected")
