"""Tests for integrations app GraphQL queries and mutations."""

from datetime import timedelta

import pytest
from django.utils import timezone

from accounts.tests.factories import (
    UserFactory,
    WorkspaceFactory,
    WorkspaceMembershipFactory,
)
from conftest import GraphQLTestClient
from messages.tests.factories import SignalFactory, ThreadFactory
from sources.tests.factories import SourceFactory

from .factories import GitHubInstallationFactory, GitHubRepositoryFactory


@pytest.mark.django_db
class TestGitHubInstallationQuery:
    """Tests for githubInstallation query."""

    def test_github_installation_returns_installation(self):
        """Test that githubInstallation query returns installation for admins."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="admin")
        installation = GitHubInstallationFactory(workspace=workspace)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query GitHubInstallation($workspaceId: ID!) {
                githubInstallation(workspaceId: $workspaceId) {
                    id
                    accountLogin
                    accountType
                    isSuspended
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert result.data["githubInstallation"] is not None
        assert result.data["githubInstallation"]["accountLogin"] == installation.account_login

    def test_github_installation_returns_none_for_member(self):
        """Test that githubInstallation returns null for non-admin members."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        GitHubInstallationFactory(workspace=workspace)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query GitHubInstallation($workspaceId: ID!) {
                githubInstallation(workspaceId: $workspaceId) {
                    id
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert result.data["githubInstallation"] is None

    def test_github_installation_returns_none_when_not_exists(self):
        """Test that githubInstallation returns null when no installation exists."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="admin")

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query GitHubInstallation($workspaceId: ID!) {
                githubInstallation(workspaceId: $workspaceId) {
                    id
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert result.data["githubInstallation"] is None


@pytest.mark.django_db
class TestGitHubRepositoriesQuery:
    """Tests for githubRepositories query."""

    def test_github_repositories_returns_repos(self):
        """Test that githubRepositories query returns repos for members."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        installation = GitHubInstallationFactory(workspace=workspace)

        GitHubRepositoryFactory.create_batch(3, installation=installation)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query GitHubRepositories($workspaceId: ID!) {
                githubRepositories(workspaceId: $workspaceId) {
                    id
                    fullName
                    syncStatus
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert len(result.data["githubRepositories"]) == 3

    def test_github_repositories_excludes_archived(self):
        """Test that githubRepositories excludes archived repositories."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        installation = GitHubInstallationFactory(workspace=workspace)

        GitHubRepositoryFactory(installation=installation, is_archived=False)
        GitHubRepositoryFactory(installation=installation, is_archived=True)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query GitHubRepositories($workspaceId: ID!) {
                githubRepositories(workspaceId: $workspaceId) {
                    id
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert len(result.data["githubRepositories"]) == 1

    def test_github_repositories_returns_empty_for_unauthenticated(self):
        """Test that githubRepositories returns empty for unauthenticated users."""
        workspace = WorkspaceFactory()
        installation = GitHubInstallationFactory(workspace=workspace)
        GitHubRepositoryFactory.create_batch(3, installation=installation)

        client = GraphQLTestClient()
        result = client.execute(
            """
            query GitHubRepositories($workspaceId: ID!) {
                githubRepositories(workspaceId: $workspaceId) {
                    id
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert result.data["githubRepositories"] == []

    def test_github_repositories_returns_empty_when_no_installation(self):
        """Test that githubRepositories returns empty when no installation exists."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query GitHubRepositories($workspaceId: ID!) {
                githubRepositories(workspaceId: $workspaceId) {
                    id
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert result.data["githubRepositories"] == []


@pytest.mark.django_db
class TestGitHubDisconnectInstallationMutation:
    """Tests for githubDisconnectInstallation mutation."""

    def test_disconnect_installation_success(self):
        """Test disconnecting a GitHub installation successfully."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="admin")
        GitHubInstallationFactory(workspace=workspace)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            mutation GithubDisconnectInstallation($workspaceId: ID!) {
                githubDisconnectInstallation(workspaceId: $workspaceId) {
                    success
                    error
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert result.data["githubDisconnectInstallation"]["success"] is True

    def test_disconnect_installation_requires_admin(self):
        """Test that disconnecting requires admin access."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        GitHubInstallationFactory(workspace=workspace)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            mutation GithubDisconnectInstallation($workspaceId: ID!) {
                githubDisconnectInstallation(workspaceId: $workspaceId) {
                    success
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is not None
        assert "Permission denied" in str(result.errors)


@pytest.mark.django_db
class TestGitHubDisconnectRepoMutation:
    """Tests for githubDisconnectRepo mutation."""

    def test_disconnect_repo_success(self):
        """Test disconnecting a GitHub repository successfully."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="admin")
        installation = GitHubInstallationFactory(workspace=workspace)
        repo = GitHubRepositoryFactory(installation=installation)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            mutation GithubDisconnectRepo($repositoryId: ID!) {
                githubDisconnectRepo(repositoryId: $repositoryId) {
                    success
                    error
                }
            }
            """,
            variables={"repositoryId": str(repo.id)},
        )

        assert result.errors is None
        assert result.data["githubDisconnectRepo"]["success"] is True

    def test_disconnect_repo_not_found(self):
        """Test disconnecting a nonexistent repository."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="admin")

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            mutation GithubDisconnectRepo($repositoryId: ID!) {
                githubDisconnectRepo(repositoryId: $repositoryId) {
                    success
                    error
                }
            }
            """,
            variables={"repositoryId": "99999"},
        )

        assert result.errors is None
        assert result.data["githubDisconnectRepo"]["success"] is False
        assert result.data["githubDisconnectRepo"]["error"] == "Repository not found"


# =============================================================================
# Unified Activity Feed Tests (US4 - Type-Safe GraphQL API)
# =============================================================================


@pytest.mark.django_db
class TestUnifiedActivityFeedQuery:
    """Tests for unifiedActivityFeed query."""

    def test_unified_feed_returns_threads_and_signals(self):
        """Test that unifiedActivityFeed returns both threads and signals."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        source = SourceFactory(workspace=workspace)

        now = timezone.now()
        ThreadFactory(workspace=workspace, source=source, activity_at=now - timedelta(hours=1))
        SignalFactory(workspace=workspace, source=source, occurred_at=now - timedelta(hours=2))
        ThreadFactory(workspace=workspace, source=source, activity_at=now - timedelta(hours=3))

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query UnifiedActivityFeed($workspaceId: ID!) {
                unifiedActivityFeed(workspaceId: $workspaceId, first: 10) {
                    items {
                        itemType
                        activityAt
                        content {
                            ... on FeedThread {
                                id
                                title
                                threadType
                            }
                            ... on FeedSignal {
                                id
                                title
                                signalType
                            }
                        }
                    }
                    pageInfo {
                        hasNextPage
                        hasPreviousPage
                    }
                    totalCount
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert result.data["unifiedActivityFeed"]["totalCount"] == 3
        assert len(result.data["unifiedActivityFeed"]["items"]) == 3

        # Check item types are correct
        item_types = [item["itemType"] for item in result.data["unifiedActivityFeed"]["items"]]
        assert "THREAD" in item_types
        assert "SIGNAL" in item_types

    def test_unified_feed_respects_chronological_order(self):
        """Test that items are returned in chronological order (most recent first)."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        source = SourceFactory(workspace=workspace)

        now = timezone.now()
        ThreadFactory(workspace=workspace, source=source, activity_at=now, title="Most Recent")
        SignalFactory(workspace=workspace, source=source, occurred_at=now - timedelta(hours=1), title="Second")
        ThreadFactory(workspace=workspace, source=source, activity_at=now - timedelta(hours=2), title="Third")

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query UnifiedActivityFeed($workspaceId: ID!) {
                unifiedActivityFeed(workspaceId: $workspaceId, first: 10) {
                    items {
                        content {
                            ... on FeedThread {
                                title
                            }
                            ... on FeedSignal {
                                title
                            }
                        }
                    }
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        titles = []
        for item in result.data["unifiedActivityFeed"]["items"]:
            content = item["content"]
            titles.append(content.get("title"))

        assert titles == ["Most Recent", "Second", "Third"]

    def test_unified_feed_requires_authentication(self):
        """Test that unifiedActivityFeed requires authentication."""
        workspace = WorkspaceFactory()

        client = GraphQLTestClient()  # No user
        result = client.execute(
            """
            query UnifiedActivityFeed($workspaceId: ID!) {
                unifiedActivityFeed(workspaceId: $workspaceId, first: 10) {
                    totalCount
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is not None
        assert "Authentication required" in str(result.errors)

    def test_unified_feed_filter_by_item_type_thread(self):
        """Test filtering feed by item type (threads only)."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        source = SourceFactory(workspace=workspace)

        now = timezone.now()
        ThreadFactory(workspace=workspace, source=source, activity_at=now)
        SignalFactory(workspace=workspace, source=source, occurred_at=now - timedelta(hours=1))

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query UnifiedActivityFeed($workspaceId: ID!, $filters: FeedFilterInput) {
                unifiedActivityFeed(workspaceId: $workspaceId, first: 10, filters: $filters) {
                    items {
                        itemType
                    }
                }
            }
            """,
            variables={
                "workspaceId": str(workspace.id),
                "filters": {"itemTypes": ["THREAD"]},
            },
        )

        assert result.errors is None
        assert len(result.data["unifiedActivityFeed"]["items"]) == 1
        assert result.data["unifiedActivityFeed"]["items"][0]["itemType"] == "THREAD"

    def test_unified_feed_filter_by_signal_type(self):
        """Test filtering feed by signal type."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        source = SourceFactory(workspace=workspace)

        now = timezone.now()
        SignalFactory(workspace=workspace, source=source, signal_type="star", occurred_at=now)
        SignalFactory(workspace=workspace, source=source, signal_type="fork", occurred_at=now - timedelta(hours=1))
        SignalFactory(workspace=workspace, source=source, signal_type="mention", occurred_at=now - timedelta(hours=2))

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query UnifiedActivityFeed($workspaceId: ID!, $filters: FeedFilterInput) {
                unifiedActivityFeed(workspaceId: $workspaceId, first: 10, filters: $filters) {
                    items {
                        content {
                            ... on FeedSignal {
                                signalType
                            }
                        }
                    }
                }
            }
            """,
            variables={
                "workspaceId": str(workspace.id),
                "filters": {"itemTypes": ["SIGNAL"], "signalTypes": ["STAR", "FORK"]},
            },
        )

        assert result.errors is None
        assert len(result.data["unifiedActivityFeed"]["items"]) == 2
        signal_types = [item["content"]["signalType"] for item in result.data["unifiedActivityFeed"]["items"]]
        assert set(signal_types) == {"STAR", "FORK"}


@pytest.mark.django_db
class TestSignalsQuery:
    """Tests for signals query."""

    def test_signals_returns_signals(self):
        """Test that signals query returns signal items."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        source = SourceFactory(workspace=workspace)

        SignalFactory.create_batch(3, workspace=workspace, source=source)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query Signals($workspaceId: ID!) {
                signals(workspaceId: $workspaceId, first: 10) {
                    items {
                        id
                        title
                        signalType
                        externalUrl
                    }
                    pageInfo {
                        hasNextPage
                    }
                    totalCount
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is None
        assert result.data["signals"]["totalCount"] == 3
        assert len(result.data["signals"]["items"]) == 3

    def test_signals_filter_by_type(self):
        """Test filtering signals by type."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        source = SourceFactory(workspace=workspace)

        now = timezone.now()
        SignalFactory(workspace=workspace, source=source, signal_type="star", occurred_at=now)
        SignalFactory(workspace=workspace, source=source, signal_type="fork", occurred_at=now - timedelta(hours=1))
        SignalFactory(workspace=workspace, source=source, signal_type="mention", occurred_at=now - timedelta(hours=2))

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query Signals($workspaceId: ID!, $signalTypes: [SignalTypeEnum!]) {
                signals(workspaceId: $workspaceId, first: 10, signalTypes: $signalTypes) {
                    items {
                        signalType
                    }
                    totalCount
                }
            }
            """,
            variables={
                "workspaceId": str(workspace.id),
                "signalTypes": ["STAR"],
            },
        )

        assert result.errors is None
        assert result.data["signals"]["totalCount"] == 1
        assert result.data["signals"]["items"][0]["signalType"] == "STAR"

    def test_signals_requires_authentication(self):
        """Test that signals requires authentication."""
        workspace = WorkspaceFactory()

        client = GraphQLTestClient()  # No user
        result = client.execute(
            """
            query Signals($workspaceId: ID!) {
                signals(workspaceId: $workspaceId, first: 10) {
                    totalCount
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

        assert result.errors is not None
        assert "Authentication required" in str(result.errors)
