"""Unit tests for github.py — Discussion operations.

Covers add_discussion_comment, create_discussion, get_discussion_comments,
get_discussion_body, and the _graphql validation surface that every
discussion helper shares.
"""
from __future__ import annotations

import json
from unittest.mock import MagicMock, patch

import pytest

from active_claude_github_mcp.github.core import GitHubError
from active_claude_github_mcp.github.discussions import (
    add_discussion_comment,
    create_discussion,
    get_discussion_body,
    get_discussion_comments,
)


TOKEN = "ghp_test_token"


def _mock_response(data: dict, status_code: int = 200):
    mock = MagicMock()
    mock.status_code = status_code
    mock.json.return_value = data
    mock.text = json.dumps(data)
    return mock


class TestGraphQLValidation:
    def test_empty_token_raises(self):
        with pytest.raises(ValueError, match="token"):
            add_discussion_comment("", "DIC_123", "body")

    def test_empty_query_raises(self):
        # Tested indirectly via empty discussion_id
        with pytest.raises(ValueError, match="discussion_id"):
            add_discussion_comment(TOKEN, "", "body")

    def test_empty_body_raises(self):
        with pytest.raises(ValueError, match="body"):
            add_discussion_comment(TOKEN, "DIC_123", "")


class TestAddDiscussionComment:
    def test_success(self):
        response_data = {
            "data": {
                "addDiscussionComment": {
                    "comment": {
                        "id": "DC_abc123",
                        "url": "https://github.com/owner/repo/discussions/1#comment-1",
                    }
                }
            }
        }
        with patch("httpx.post", return_value=_mock_response(response_data)):
            result = add_discussion_comment(TOKEN, "D_abc123", "Hello")
        assert result["id"] == "DC_abc123"
        assert "github.com" in result["url"]

    def test_github_errors_raises(self):
        response_data = {"errors": [{"message": "Forbidden"}]}
        with patch("httpx.post", return_value=_mock_response(response_data)):
            with pytest.raises(GitHubError, match="Forbidden"):
                add_discussion_comment(TOKEN, "D_abc123", "Hello")

    def test_http_error_raises(self):
        with patch("httpx.post", return_value=_mock_response({}, status_code=401)):
            with pytest.raises(GitHubError, match="HTTP 401"):
                add_discussion_comment(TOKEN, "D_abc123", "Hello")


class TestCreateDiscussion:
    def test_success(self):
        response_data = {
            "data": {
                "createDiscussion": {
                    "discussion": {
                        "id": "D_new123",
                        "number": 5,
                        "url": "https://github.com/owner/repo/discussions/5",
                    }
                }
            }
        }
        with patch("httpx.post", return_value=_mock_response(response_data)):
            result = create_discussion(
                TOKEN, "R_repo123", "DIC_cat123", "Test Title", "Test body"
            )
        assert result["id"] == "D_new123"
        assert result["number"] == 5

    def test_empty_title_raises(self):
        with pytest.raises(ValueError, match="title"):
            create_discussion(TOKEN, "R_repo123", "DIC_cat123", "", "body")


class TestGetDiscussionComments:
    def test_success(self):
        response_data = {
            "data": {
                "node": {
                    "comments": {
                        "nodes": [
                            {"id": "DC_1", "body": "First", "createdAt": "2026-01-01"},
                            {"id": "DC_2", "body": "Second", "createdAt": "2026-01-02"},
                        ]
                    }
                }
            }
        }
        with patch("httpx.post", return_value=_mock_response(response_data)):
            comments = get_discussion_comments(TOKEN, "D_abc123")
        assert len(comments) == 2
        assert comments[0]["id"] == "DC_1"

    def test_discussion_not_found_raises(self):
        response_data = {"data": {"node": None}}
        with patch("httpx.post", return_value=_mock_response(response_data)):
            with pytest.raises(GitHubError, match="not found"):
                get_discussion_comments(TOKEN, "D_notexist")

    def test_invalid_last_n_raises(self):
        with pytest.raises(ValueError, match="last_n"):
            get_discussion_comments(TOKEN, "D_abc123", last_n=0)

    def test_last_n_too_large_raises(self):
        with pytest.raises(ValueError, match="last_n"):
            get_discussion_comments(TOKEN, "D_abc123", last_n=101)


class TestGetDiscussionBody:
    def test_success(self):
        response_data = {"data": {"node": {"body": "# Hello\n\nTable of Contents"}}}
        with patch("httpx.post", return_value=_mock_response(response_data)):
            body = get_discussion_body(TOKEN, "D_abc123")
        assert body.startswith("# Hello")

    def test_missing_discussion_raises(self):
        response_data = {"data": {"node": None}}
        with patch("httpx.post", return_value=_mock_response(response_data)):
            with pytest.raises(GitHubError, match="not found"):
                get_discussion_body(TOKEN, "D_missing")

    def test_empty_id_raises(self):
        with pytest.raises(ValueError, match="discussion_id"):
            get_discussion_body(TOKEN, "")
if __name__ == "__main__":
    import sys
    import pytest
    sys.exit(pytest.main([__file__, "-v"]))
