"""Unit tests for QuestraAutomation high-level client."""

from __future__ import annotations

import pytest

from questra_automation import QuestraAutomation
from questra_automation.models import ExecutionInitiator


@pytest.mark.unit
class TestQuestraAutomationInit:
    """Tests für QuestraAutomation Initialisierung."""

    def test_init_success(self, mock_auth_client):
        """Test erfolgreiche Initialisierung."""
        client = QuestraAutomation(
            graphql_url="https://automation.example.com/graphql",
            auth_client=mock_auth_client,
        )

        assert client.graphql_url == "https://automation.example.com/graphql"
        assert client.is_authenticated() is True
        mock_auth_client.is_authenticated.assert_called()

    def test_init_not_authenticated(self, mock_auth_client):
        """Test Initialisierung mit nicht-authentifiziertem Client."""
        mock_auth_client.is_authenticated.return_value = False

        with pytest.raises(ValueError, match="not authenticated"):
            QuestraAutomation(
                graphql_url="https://automation.example.com/graphql",
                auth_client=mock_auth_client,
            )

    def test_repr(self, mock_auth_client):
        """Test String-Repräsentation."""
        client = QuestraAutomation(
            graphql_url="https://automation.example.com/graphql",
            auth_client=mock_auth_client,
        )

        repr_str = repr(client)
        assert "QuestraAutomation" in repr_str
        assert "https://automation.example.com/graphql" in repr_str
        assert "authenticated" in repr_str


@pytest.mark.unit
class TestQuestraAutomationQueries:
    """Tests für Query-Operationen über High-Level Client."""

    def test_get_workspaces(self, mock_auth_client, mock_graphql_execute, workspaces_response):
        """Test get_workspaces über Client."""
        # Setup Transport-Mock
        from unittest.mock import patch

        with patch("questra_automation.client.GraphQLTransport") as mock_transport_class:
            mock_transport = mock_transport_class.return_value
            mock_transport.execute.return_value = workspaces_response

            client = QuestraAutomation(
                graphql_url="https://automation.example.com/graphql",
                auth_client=mock_auth_client,
            )

            # Query ausführen
            workspaces = client.queries.get_workspaces(first=10)

            # Assertions
            assert workspaces.total_count == 3
            assert len(workspaces.nodes) == 3
            assert workspaces.nodes[0].name == "dev-workspace"

            # Transport execute wurde aufgerufen
            mock_transport.execute.assert_called_once()

    def test_get_service_info(self, mock_auth_client, service_info_response):
        """Test get_service_info über Client."""
        from unittest.mock import patch

        with patch("questra_automation.client.GraphQLTransport") as mock_transport_class:
            mock_transport = mock_transport_class.return_value
            mock_transport.execute.return_value = service_info_response

            client = QuestraAutomation(
                graphql_url="https://automation.example.com/graphql",
                auth_client=mock_auth_client,
            )

            # Query ausführen
            service_info = client.queries.get_service_info()

            # Assertions
            assert service_info.name == "Questra Automation Service"
            assert service_info.version == "1.2.3"
            assert "build" in service_info.informational_version


@pytest.mark.unit
class TestQuestraAutomationMutations:
    """Tests für Mutation-Operationen über High-Level Client."""

    def test_execute_automation(
        self, mock_auth_client, execute_success_response
    ):
        """Test execute_automation über Client."""
        from unittest.mock import patch

        with patch("questra_automation.client.GraphQLTransport") as mock_transport_class:
            mock_transport = mock_transport_class.return_value
            mock_transport.execute.return_value = execute_success_response

            client = QuestraAutomation(
                graphql_url="https://automation.example.com/graphql",
                auth_client=mock_auth_client,
            )

            # Mutation ausführen
            result = client.mutations.execute_automation(
                workspace_name="dev-workspace",
                automation_path="scripts/daily_sync.py",
                initiator_type=ExecutionInitiator.MANUAL,
                arguments=[{"name": "source", "value": "system-a"}],
            )

            # Assertions
            assert str(result.id) == "12345678-1234-1234-1234-123456789012"
            mock_transport.execute.assert_called_once()

    def test_create_workspace(
        self, mock_auth_client, create_workspace_success_response
    ):
        """Test create_workspace über Client."""
        from unittest.mock import patch

        with patch("questra_automation.client.GraphQLTransport") as mock_transport_class:
            mock_transport = mock_transport_class.return_value
            mock_transport.execute.return_value = create_workspace_success_response

            client = QuestraAutomation(
                graphql_url="https://automation.example.com/graphql",
                auth_client=mock_auth_client,
            )

            # Mutation ausführen
            result = client.mutations.create_workspace(
                repository_name="main-repo",
                name="new-workspace",
                branch_name="main",
                commit="abc123",
            )

            # Assertions
            assert result.name == "new-workspace"


@pytest.mark.unit
class TestQuestraAutomationRawExecute:
    """Tests für execute_raw Methode."""

    def test_execute_raw(self, mock_auth_client):
        """Test execute_raw für Custom-Queries."""
        from unittest.mock import patch

        custom_response = {"customQuery": {"data": "test"}}

        with patch("questra_automation.client.GraphQLTransport") as mock_transport_class:
            mock_transport = mock_transport_class.return_value
            mock_transport.execute.return_value = custom_response

            client = QuestraAutomation(
                graphql_url="https://automation.example.com/graphql",
                auth_client=mock_auth_client,
            )

            # Raw Query ausführen
            result = client.execute_raw(
                query="query { customQuery { data } }",
                variables={"param": "value"},
            )

            # Assertions
            assert result["customQuery"]["data"] == "test"
            mock_transport.execute.assert_called_once()
            call_args = mock_transport.execute.call_args
            assert "customQuery" in call_args[0][0]
            assert call_args[0][1]["param"] == "value"


@pytest.mark.unit
class TestQuestraAutomationReauthentication:
    """Tests für Reauthentication."""

    def test_reauthenticate(self, mock_auth_client):
        """Test reauthenticate Methode."""
        from unittest.mock import patch

        with patch("questra_automation.client.GraphQLTransport"):
            client = QuestraAutomation(
                graphql_url="https://automation.example.com/graphql",
                auth_client=mock_auth_client,
            )

            # Reauthenticate aufrufen
            client.reauthenticate()

            # Auth-Client reauthenticate wurde aufgerufen
            mock_auth_client.reauthenticate.assert_called_once()

    def test_is_authenticated(self, mock_auth_client):
        """Test is_authenticated Methode."""
        from unittest.mock import patch

        with patch("questra_automation.client.GraphQLTransport"):
            client = QuestraAutomation(
                graphql_url="https://automation.example.com/graphql",
                auth_client=mock_auth_client,
            )

            # is_authenticated prüfen
            assert client.is_authenticated() is True
            mock_auth_client.is_authenticated.assert_called()

            # Status ändern
            mock_auth_client.is_authenticated.return_value = False
            assert client.is_authenticated() is False
