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

import pytest

from accounts.tests.factories import UserFactory, WorkspaceFactory, WorkspaceMembershipFactory
from conftest import GraphQLTestClient
from sources.tests.factories import SourceFactory

from .factories import MessageFactory, TagFactory, ThreadFactory


@pytest.mark.django_db
class TestThreadsQuery:
    """Tests for threads query."""

    def test_threads_returns_workspace_threads(self):
        """Test that threads query returns all threads in a workspace."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace)
        source = SourceFactory(workspace=workspace)

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

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query Threads($workspaceId: ID!) {
                threads(workspaceId: $workspaceId) {
                    id
                    title
                    status
                }
            }
            """,
            variables={"workspaceId": str(workspace.id)},
        )

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

    def test_threads_filters_by_status(self):
        """Test that threads can be filtered by status."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace)
        source = SourceFactory(workspace=workspace)

        ThreadFactory(workspace=workspace, source=source, status="open")
        ThreadFactory(workspace=workspace, source=source, status="open")
        ThreadFactory(workspace=workspace, source=source, status="closed")

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query Threads($workspaceId: ID!, $status: ThreadStatus) {
                threads(workspaceId: $workspaceId, status: $status) {
                    id
                    status
                }
            }
            """,
            variables={"workspaceId": str(workspace.id), "status": "OPEN"},
        )

        assert result.errors is None
        assert len(result.data["threads"]) == 2
        assert all(t["status"] == "OPEN" for t in result.data["threads"])

    def test_threads_returns_empty_for_unauthenticated(self):
        """Test that threads query returns empty for unauthenticated users."""
        workspace = WorkspaceFactory()
        source = SourceFactory(workspace=workspace)
        ThreadFactory.create_batch(3, workspace=workspace, source=source)

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

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


@pytest.mark.django_db
class TestThreadQuery:
    """Tests for thread query."""

    def test_thread_returns_single_thread(self):
        """Test that thread query returns a specific thread."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace)
        source = SourceFactory(workspace=workspace)
        thread = ThreadFactory(workspace=workspace, source=source, title="Bug Report")

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query Thread($id: ID!) {
                thread(id: $id) {
                    id
                    title
                }
            }
            """,
            variables={"id": str(thread.id)},
        )

        assert result.errors is None
        assert result.data["thread"]["title"] == "Bug Report"


@pytest.mark.django_db
class TestMessagesQuery:
    """Tests for messages query."""

    def test_messages_returns_thread_messages(self):
        """Test that messages query returns all messages in a thread."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace)
        source = SourceFactory(workspace=workspace)
        thread = ThreadFactory(workspace=workspace, source=source)

        MessageFactory.create_batch(3, thread=thread)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            query Messages($threadId: ID!) {
                messages(threadId: $threadId) {
                    id
                    content
                }
            }
            """,
            variables={"threadId": str(thread.id)},
        )

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


@pytest.mark.django_db
class TestTagsQuery:
    """Tests for tags query."""

    def test_tags_returns_workspace_tags(self):
        """Test that tags query returns all tags in a workspace."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace)

        TagFactory.create_batch(3, workspace=workspace)

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

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


@pytest.mark.django_db
class TestCreateTagMutation:
    """Tests for createTag mutation."""

    def test_create_tag_success(self):
        """Test creating a tag successfully."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            mutation CreateTag($input: CreateTagInput!) {
                createTag(input: $input) {
                    id
                    name
                }
            }
            """,
            variables={"input": {"workspaceId": str(workspace.id), "name": "feature-request"}},
        )

        assert result.errors is None
        assert result.data["createTag"]["name"] == "feature-request"

    def test_create_tag_duplicate_fails(self):
        """Test that duplicate tag names fail."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        TagFactory(workspace=workspace, name="existing-tag")

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            mutation CreateTag($input: CreateTagInput!) {
                createTag(input: $input) {
                    id
                }
            }
            """,
            variables={"input": {"workspaceId": str(workspace.id), "name": "existing-tag"}},
        )

        assert result.errors is not None
        assert "already exists" in str(result.errors)


@pytest.mark.django_db
class TestDeleteTagMutation:
    """Tests for deleteTag mutation."""

    def test_delete_tag_success(self):
        """Test deleting a tag successfully."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="admin")
        tag = TagFactory(workspace=workspace)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            mutation DeleteTag($id: ID!) {
                deleteTag(id: $id)
            }
            """,
            variables={"id": str(tag.id)},
        )

        assert result.errors is None
        assert result.data["deleteTag"] is True


@pytest.mark.django_db
class TestUpdateThreadMutation:
    """Tests for updateThread mutation."""

    def test_update_thread_status(self):
        """Test updating a thread status."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        source = SourceFactory(workspace=workspace)
        thread = ThreadFactory(workspace=workspace, source=source, status="open")

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            mutation UpdateThread($id: ID!, $input: UpdateThreadInput!) {
                updateThread(id: $id, input: $input) {
                    id
                    status
                }
            }
            """,
            variables={"id": str(thread.id), "input": {"status": "CLOSED"}},
        )

        assert result.errors is None
        assert result.data["updateThread"]["status"] == "CLOSED"


@pytest.mark.django_db
class TestCreateMessageMutation:
    """Tests for createMessage mutation."""

    def test_create_message_success(self):
        """Test creating a message successfully."""
        user = UserFactory()
        workspace = WorkspaceFactory()
        WorkspaceMembershipFactory(user=user, workspace=workspace, role="member")
        source = SourceFactory(workspace=workspace)
        thread = ThreadFactory(workspace=workspace, source=source)

        client = GraphQLTestClient(user=user)
        result = client.execute(
            """
            mutation CreateMessage($input: CreateMessageInput!) {
                createMessage(input: $input) {
                    id
                    content
                }
            }
            """,
            variables={"input": {"threadId": str(thread.id), "content": "New message"}},
        )

        assert result.errors is None
        assert result.data["createMessage"]["content"] == "New message"
