"""
Integration tests for tracker methods called by the API.
"""

from unittest.mock import MagicMock, patch, AsyncMock
from unittest import IsolatedAsyncioTestCase

from preloop.sync.trackers.github import GitHubTracker
from preloop.sync.trackers.gitlab import GitLabTracker
from preloop.sync.trackers.jira import JiraTracker


class TestTrackerApiIntegration(IsolatedAsyncioTestCase):
    """Test integration between API and tracker methods."""

    async def test_github_tracker_get_issue_api_integration(self):
        """Test GitHub tracker get_issue method works with API connection details format."""
        # Arrange - simulate how get_tracker_client creates connection_details for GitHub
        connection_details = {
            "owner": "testowner",
            "repo": "testrepo",
            "url": "https://github.com",
        }

        tracker = GitHubTracker("tracker-1", "api-key", connection_details)

        # Mock the _make_request method directly instead of httpx
        issue_data = {
            "id": 12345,
            "number": 1,
            "title": "Test Issue",
            "body": "Issue description",
            "state": "open",
            "created_at": "2023-01-01T10:00:00Z",
            "updated_at": "2023-01-02T11:00:00Z",
            "html_url": "https://github.com/testowner/testrepo/issues/1",
            "url": "https://api.github.com/repos/testowner/testrepo/issues/1",
            "labels": [{"name": "bug"}],
            "assignees": [
                {
                    "login": "user1",
                    "id": 123,
                    "avatar_url": "https://example.com/avatar.png",
                }
            ],
            "assignee": {
                "login": "user1",
                "id": 123,
                "avatar_url": "https://example.com/avatar.png",
            },
            "user": {
                "login": "reporter",
                "id": 456,
                "avatar_url": "https://example.com/reporter.png",
            },
        }

        tracker._make_request = AsyncMock(return_value=issue_data)

        # Act
        result = await tracker.get_issue("1")

        # Assert - Now result is an Issue object, not a dict
        self.assertEqual(result.id, "12345")
        self.assertEqual(result.key, "testowner/testrepo#1")
        self.assertEqual(result.title, "Test Issue")

        # Verify the correct API endpoint was called
        expected_endpoint = "repos/testowner/testrepo/issues/1"
        tracker._make_request.assert_called_once_with(expected_endpoint)

    async def test_github_tracker_get_comments_api_integration(self):
        """Test GitHub tracker get_comments method works with API connection details format."""
        # Arrange
        connection_details = {
            "owner": "testowner",
            "repo": "testrepo",
            "url": "https://github.com",
        }

        tracker = GitHubTracker("tracker-1", "api-key", connection_details)

        comments_data = [
            {
                "id": 1001,
                "body": "Test comment",
                "user": {
                    "id": 101,
                    "login": "commenter1",
                    "avatar_url": "https://avatars.github.com/u/101",
                },
                "created_at": "2023-01-01T12:00:00Z",
                "updated_at": "2023-01-01T12:00:00Z",
                "html_url": "https://github.com/testowner/testrepo/issues/1#issuecomment-1001",
            }
        ]

        tracker._make_request = AsyncMock(return_value=comments_data)

        # Act
        result = await tracker.get_comments("1")

        # Assert
        self.assertEqual(len(result), 1)
        self.assertEqual(result[0].id, "1001")
        self.assertEqual(result[0].body, "Test comment")

        # Verify the correct API endpoint was called
        expected_endpoint = "repos/testowner/testrepo/issues/1/comments"
        tracker._make_request.assert_called_once_with(
            expected_endpoint, params={"per_page": 100}
        )

    @patch("preloop.sync.trackers.gitlab.gitlab.Gitlab")
    async def test_gitlab_tracker_get_issue_api_integration(
        self, mock_gitlab_constructor
    ):
        """Test GitLab tracker get_issue method works with API connection details format."""
        # Arrange - simulate how get_tracker_client creates connection_details for GitLab
        connection_details = {
            "project_id": "123",
            "url": "https://gitlab.com",
        }

        mock_gl_instance = MagicMock()
        mock_gitlab_constructor.return_value = mock_gl_instance

        mock_project = MagicMock()
        mock_project.path_with_namespace = "testgroup/testproject"

        mock_issue = MagicMock()
        mock_issue.id = 12345
        mock_issue.iid = 1
        mock_issue.title = "Test Issue"
        mock_issue.description = "Issue description"
        mock_issue.state = "opened"
        mock_issue.created_at = "2023-01-01T10:00:00.000Z"
        mock_issue.updated_at = "2023-01-02T11:00:00.000Z"
        mock_issue.web_url = "https://gitlab.com/testgroup/testproject/-/issues/1"
        mock_issue.labels = ["bug"]
        mock_issue.assignees = [{"username": "user1"}]
        # Add attributes dict for the parser
        mock_issue.attributes = {
            "id": 12345,
            "iid": 1,
            "title": "Test Issue",
            "description": "Issue description",
            "state": "opened",
            "created_at": "2023-01-01T10:00:00.000Z",
            "updated_at": "2023-01-02T11:00:00.000Z",
            "web_url": "https://gitlab.com/testgroup/testproject/-/issues/1",
            "labels": ["bug"],
            "assignee": None,
            "assignees": [],
            "author": {
                "id": 123,
                "name": "Author",
                "avatar_url": "https://example.com/avatar.png",
            },
            "_links": {"self": "https://gitlab.com/api/v4/projects/123/issues/1"},
        }

        tracker = GitLabTracker("tracker-1", "api-key", connection_details)
        tracker._make_request = AsyncMock()
        tracker._make_request.side_effect = [mock_project, mock_issue]

        # Act
        result = await tracker.get_issue("1")

        # Assert - Now result is an Issue object, not a dict
        self.assertEqual(result.id, "12345")
        self.assertEqual(result.key, "testgroup/testproject#1")
        self.assertEqual(result.title, "Test Issue")

        # Verify the project_id from connection_details was used
        tracker._make_request.assert_any_call(mock_gl_instance.projects.get, "123")

    @patch("preloop.sync.trackers.gitlab.gitlab.Gitlab")
    async def test_gitlab_tracker_get_comments_api_integration(
        self, mock_gitlab_constructor
    ):
        """Test GitLab tracker get_comments method works with API connection details format."""
        # Arrange
        connection_details = {
            "project_id": "123",
            "url": "https://gitlab.com",
        }

        mock_gl_instance = MagicMock()
        mock_gitlab_constructor.return_value = mock_gl_instance

        mock_project = MagicMock()
        mock_project.path_with_namespace = "testgroup/testproject"

        mock_issue = MagicMock()
        mock_issue.id = 12345
        mock_issue.web_url = "https://gitlab.com/testgroup/testproject/-/issues/1"

        mock_note = MagicMock()
        mock_note.id = 1001
        mock_note.body = "Test comment"
        mock_note.system = False
        mock_note.created_at = "2023-01-01T12:00:00.000Z"
        mock_note.updated_at = "2023-01-01T12:00:00.000Z"
        mock_note.author = {
            "id": 101,
            "username": "commenter1",
            "avatar_url": "https://gitlab.com/avatars/101.png",
        }

        tracker = GitLabTracker("tracker-1", "api-key", connection_details)
        tracker._make_request = AsyncMock()
        tracker._make_request.side_effect = [mock_project, mock_issue, [mock_note]]

        # Act
        result = await tracker.get_comments("1")

        # Assert
        self.assertEqual(len(result), 1)
        self.assertEqual(result[0].id, "1001")
        self.assertEqual(result[0].body, "Test comment")

        # Verify the project_id from connection_details was used
        tracker._make_request.assert_any_call(mock_gl_instance.projects.get, "123")

    async def test_jira_tracker_get_issue_api_integration(self):
        """Test Jira tracker get_issue method works with API connection details format."""
        # Arrange - simulate how get_tracker_client creates connection_details for Jira
        connection_details = {
            "project_key": "TEST",
            "url": "https://test.atlassian.net",
            "username": "test@example.com",
        }

        tracker = JiraTracker("tracker-1", "api-token", connection_details)
        tracker.base_url = "https://test.atlassian.net"

        issue_data = {
            "id": "12345",
            "key": "TEST-123",
            "fields": {
                "summary": "Test Issue",
                "description": "Issue description",
                "status": {"id": "1", "name": "Open", "statusCategory": {"key": "new"}},
                "created": "2023-01-01T10:00:00.000+0000",
                "updated": "2023-01-02T11:00:00.000+0000",
                "labels": ["bug"],
                "assignee": {
                    "accountId": "123",
                    "displayName": "testuser",
                    "avatarUrls": {"48x48": "https://example.com/avatar.png"},
                },
                "project": {"key": "TEST"},
            },
        }

        tracker._make_request = AsyncMock(return_value=issue_data)

        # Act
        result = await tracker.get_issue("TEST-123")

        # Assert - Now result is an Issue object, not a dict
        self.assertEqual(result.id, "12345")
        self.assertEqual(result.key, "TEST-123")
        self.assertEqual(result.title, "Test Issue")
        self.assertEqual(result.url, "https://test.atlassian.net/browse/TEST-123")

        # Verify the correct API endpoint was called
        tracker._make_request.assert_called_once_with(
            "GET", "issue/TEST-123", api_version="3"
        )

    async def test_jira_tracker_get_comments_api_integration(self):
        """Test Jira tracker get_comments method works with API connection details format."""
        # Arrange
        connection_details = {
            "project_key": "TEST",
            "url": "https://test.atlassian.net",
            "username": "test@example.com",
        }

        tracker = JiraTracker("tracker-1", "api-token", connection_details)
        tracker.base_url = "https://test.atlassian.net"

        comments_data = {
            "comments": [
                {
                    "id": "1001",
                    "body": "Test comment",
                    "created": "2023-01-01T12:00:00.000+0000",
                    "updated": "2023-01-01T12:00:00.000+0000",
                    "author": {
                        "accountId": "101",
                        "displayName": "Test User",
                        "avatarUrls": {"48x48": "https://avatar.png"},
                    },
                }
            ]
        }

        tracker._make_request = AsyncMock(return_value=comments_data)

        # Act
        result = await tracker.get_comments("TEST-123")

        # Assert
        self.assertEqual(len(result), 1)
        self.assertEqual(result[0].id, "1001")
        self.assertEqual(result[0].body, "Test comment")

        # Verify the correct API endpoint was called
        tracker._make_request.assert_called_once_with(
            "GET", "issue/TEST-123/comment", api_version="3"
        )

    async def test_tracker_get_projects_method_name_consistency(self):
        """Test that all trackers have get_projects method (not list_projects)."""
        # This test ensures the API fix we made is correct

        # Test GitHub tracker has get_projects
        github_tracker = GitHubTracker(
            "tracker-1", "api-key", {"owner": "test", "repo": "test"}
        )
        self.assertTrue(hasattr(github_tracker, "get_projects"))
        self.assertFalse(hasattr(github_tracker, "list_projects"))

        # Test GitLab tracker has get_projects
        with patch("preloop.sync.trackers.gitlab.gitlab.Gitlab"):
            gitlab_tracker = GitLabTracker(
                "tracker-1", "api-key", {"url": "https://gitlab.com"}
            )
            self.assertTrue(hasattr(gitlab_tracker, "get_projects"))
            self.assertFalse(hasattr(gitlab_tracker, "list_projects"))

        # Test Jira tracker has get_projects
        jira_tracker = JiraTracker(
            "tracker-1",
            "api-key",
            {"url": "https://test.atlassian.net", "username": "test@example.com"},
        )
        self.assertTrue(hasattr(jira_tracker, "get_projects"))
        self.assertFalse(hasattr(jira_tracker, "list_projects"))

    async def test_all_trackers_have_required_methods(self):
        """Test that all trackers implement the required get_issue and get_comments methods."""
        # Test GitHub tracker
        github_tracker = GitHubTracker(
            "tracker-1", "api-key", {"owner": "test", "repo": "test"}
        )
        self.assertTrue(hasattr(github_tracker, "get_issue"))
        self.assertTrue(hasattr(github_tracker, "get_comments"))
        self.assertTrue(callable(github_tracker.get_issue))
        self.assertTrue(callable(github_tracker.get_comments))

        # Test GitLab tracker
        with patch("preloop.sync.trackers.gitlab.gitlab.Gitlab"):
            gitlab_tracker = GitLabTracker(
                "tracker-1", "api-key", {"url": "https://gitlab.com"}
            )
            self.assertTrue(hasattr(gitlab_tracker, "get_issue"))
            self.assertTrue(hasattr(gitlab_tracker, "get_comments"))
            self.assertTrue(callable(gitlab_tracker.get_issue))
            self.assertTrue(callable(gitlab_tracker.get_comments))

        # Test Jira tracker
        jira_tracker = JiraTracker(
            "tracker-1",
            "api-key",
            {"url": "https://test.atlassian.net", "username": "test@example.com"},
        )
        self.assertTrue(hasattr(jira_tracker, "get_issue"))
        self.assertTrue(hasattr(jira_tracker, "get_comments"))
        self.assertTrue(callable(jira_tracker.get_issue))
        self.assertTrue(callable(jira_tracker.get_comments))
