"""
Tests for team management functionality
"""

import pytest
import json
from unittest.mock import patch, AsyncMock, MagicMock
from datadog_mcp.tools import get_teams
from datadog_mcp.utils import datadog_client
from mcp.types import CallToolResult, TextContent


class TestTeamsToolDefinition:
    """Test the get_teams tool definition"""
    
    def test_get_teams_tool_definition(self):
        """Test that get_teams tool definition is properly structured"""
        tool_def = get_teams.get_tool_definition()
        
        assert tool_def.name == "get_teams"
        assert "team" in tool_def.description.lower()
        assert hasattr(tool_def, 'inputSchema')
        
        # Check schema structure
        schema = tool_def.inputSchema
        assert "properties" in schema
        
        properties = schema["properties"]
        expected_params = ["team_name", "include_members", "format"]
        for param in expected_params:
            assert param in properties, f"Parameter {param} missing from schema"


class TestTeamsRetrieval:
    """Test team data retrieval functionality"""
    
    @pytest.mark.asyncio
    async def test_fetch_teams_basic(self):
        """Test basic team fetching functionality"""
        mock_response_data = {
            "data": [
                {
                    "id": "team-123",
                    "type": "teams",
                    "attributes": {
                        "name": "Backend Team",
                        "description": "Backend development team",
                        "handle": "backend-team",
                        "summary": "Responsible for API development"
                    },
                    "relationships": {
                        "users": {
                            "data": [
                                {"id": "user-1", "type": "users"},
                                {"id": "user-2", "type": "users"}
                            ]
                        }
                    }
                }
            ],
            "included": [
                {
                    "id": "user-1",
                    "type": "users",
                    "attributes": {
                        "name": "John Doe",
                        "email": "john@example.com",
                        "handle": "john.doe"
                    }
                },
                {
                    "id": "user-2", 
                    "type": "users",
                    "attributes": {
                        "name": "Jane Smith",
                        "email": "jane@example.com", 
                        "handle": "jane.smith"
                    }
                }
            ]
        }
        
        with patch('datadog_mcp.utils.datadog_client.httpx.AsyncClient') as mock_client:
            mock_client.return_value.__aenter__.return_value.get.return_value.json.return_value = mock_response_data
            mock_client.return_value.__aenter__.return_value.get.return_value.raise_for_status.return_value = None
            
            result = await datadog_client.fetch_teams()
            
            assert isinstance(result, dict)
            assert "teams" in result
            assert "users" in result
            assert len(result["teams"]) > 0
    
    @pytest.mark.asyncio
    async def test_fetch_specific_team(self):
        """Test fetching a specific team by name"""
        team_name = "Backend Team"
        
        mock_response_data = {
            "data": [
                {
                    "id": "team-123",
                    "type": "teams", 
                    "attributes": {
                        "name": "Backend Team",
                        "handle": "backend-team"
                    }
                }
            ]
        }
        
        with patch('datadog_mcp.utils.datadog_client.httpx.AsyncClient') as mock_client:
            mock_client.return_value.__aenter__.return_value.get.return_value.json.return_value = mock_response_data
            mock_client.return_value.__aenter__.return_value.get.return_value.raise_for_status.return_value = None
            
            result = await datadog_client.fetch_teams(team_name=team_name)
            
            assert isinstance(result, dict)
            # Verify the request was made with team filter
            mock_client.return_value.__aenter__.return_value.get.assert_called_once()
    
    @pytest.mark.asyncio
    async def test_fetch_teams_with_members(self):
        """Test fetching teams with member details"""
        include_members = True
        
        mock_response_data = {
            "data": [
                {
                    "id": "team-123",
                    "type": "teams",
                    "attributes": {
                        "name": "Frontend Team"
                    },
                    "relationships": {
                        "users": {
                            "data": [{"id": "user-1", "type": "users"}]
                        }
                    }
                }
            ],
            "included": [
                {
                    "id": "user-1",
                    "type": "users",
                    "attributes": {
                        "name": "Alice Johnson",
                        "email": "alice@example.com"
                    }
                }
            ]
        }
        
        with patch('datadog_mcp.utils.datadog_client.httpx.AsyncClient') as mock_client:
            mock_client.return_value.__aenter__.return_value.get.return_value.json.return_value = mock_response_data
            mock_client.return_value.__aenter__.return_value.get.return_value.raise_for_status.return_value = None
            
            result = await datadog_client.fetch_teams(include_members=include_members)
            
            assert isinstance(result, dict)
            assert "teams" in result
            assert "users" in result
            assert len(result["users"]) > 0


class TestTeamsToolHandler:
    """Test the get_teams tool handler"""
    
    @pytest.mark.asyncio
    async def test_handle_teams_request_success(self):
        """Test successful teams request handling"""
        mock_request = MagicMock()
        mock_request.arguments = {
            "include_members": True,
            "format": "table"
        }
        
        mock_teams_data = {
            "teams": [
                {
                    "id": "team-123",
                    "name": "DevOps Team",
                    "handle": "devops",
                    "description": "Infrastructure and deployment team",
                    "member_count": 3
                }
            ],
            "users": [
                {
                    "id": "user-1",
                    "name": "Bob Wilson",
                    "email": "bob@example.com",
                    "teams": ["team-123"]
                }
            ]
        }
        
        with patch('datadog_mcp.utils.datadog_client.fetch_teams', new_callable=AsyncMock) as mock_fetch:
            mock_fetch.return_value = mock_teams_data
            
            result = await get_teams.handle_call(mock_request)
            
            assert isinstance(result, CallToolResult)
            assert result.isError is False
            assert len(result.content) > 0
            assert isinstance(result.content[0], TextContent)
            
            content_text = result.content[0].text
            assert "DevOps Team" in content_text or "devops" in content_text.lower()
    
    @pytest.mark.asyncio
    async def test_handle_teams_request_specific_team(self):
        """Test teams request for specific team"""
        mock_request = MagicMock()
        mock_request.arguments = {
            "team_name": "Security Team",
            "include_members": True,
            "format": "detailed"
        }
        
        mock_teams_data = {
            "teams": [
                {
                    "id": "team-456",
                    "name": "Security Team",
                    "handle": "security",
                    "description": "Application security team"
                }
            ],
            "users": []
        }
        
        with patch('datadog_mcp.utils.datadog_client.fetch_teams', new_callable=AsyncMock) as mock_fetch:
            mock_fetch.return_value = mock_teams_data
            
            result = await get_teams.handle_call(mock_request)
            
            assert isinstance(result, CallToolResult)
            assert result.isError is False
            
            # Verify specific team was requested
            mock_fetch.assert_called_once()
            call_args, call_kwargs = mock_fetch.call_args
            assert call_kwargs.get("team_name") == "Security Team"
    
    @pytest.mark.asyncio
    async def test_handle_teams_request_json_format(self):
        """Test teams request with JSON format"""
        mock_request = MagicMock()
        mock_request.arguments = {
            "format": "json",
            "include_members": False
        }
        
        mock_teams_data = {
            "teams": [
                {
                    "id": "team-789",
                    "name": "QA Team",
                    "handle": "qa"
                }
            ],
            "users": []
        }
        
        with patch('datadog_mcp.utils.datadog_client.fetch_teams', new_callable=AsyncMock) as mock_fetch:
            mock_fetch.return_value = mock_teams_data
            
            result = await get_teams.handle_call(mock_request)
            
            assert isinstance(result, CallToolResult)
            assert result.isError is False
            
            content_text = result.content[0].text
            # Should be valid JSON when format is json
            if mock_request.arguments.get("format") == "json":
                try:
                    json.loads(content_text)
                except json.JSONDecodeError:
                    pytest.fail("Response should be valid JSON when format=json")
    
    @pytest.mark.asyncio
    async def test_handle_teams_request_error(self):
        """Test error handling in teams requests"""
        mock_request = MagicMock()
        mock_request.arguments = {
            "team_name": "NonexistentTeam"
        }
        
        with patch('datadog_mcp.utils.datadog_client.fetch_teams', new_callable=AsyncMock) as mock_fetch:
            mock_fetch.side_effect = Exception("Team not found")
            
            result = await get_teams.handle_call(mock_request)
            
            assert isinstance(result, CallToolResult)
            assert result.isError is True
            assert len(result.content) > 0
            assert "error" in result.content[0].text.lower()
    
    @pytest.mark.asyncio
    async def test_handle_teams_request_empty_results(self):
        """Test handling when no teams are found"""
        mock_request = MagicMock()
        mock_request.arguments = {
            "team_name": "EmptyResults"
        }
        
        mock_teams_data = {
            "teams": [],
            "users": []
        }
        
        with patch('datadog_mcp.utils.datadog_client.fetch_teams', new_callable=AsyncMock) as mock_fetch:
            mock_fetch.return_value = mock_teams_data
            
            result = await get_teams.handle_call(mock_request)
            
            assert isinstance(result, CallToolResult)
            assert result.isError is False
            assert len(result.content) > 0
            
            content_text = result.content[0].text
            assert "no teams" in content_text.lower() or "empty" in content_text.lower()


class TestTeamsFormatting:
    """Test team data formatting"""
    
    def test_teams_table_formatting(self):
        """Test teams table formatting"""
        sample_teams = [
            {
                "id": "team-1",
                "name": "Backend Team",
                "handle": "backend",
                "description": "API development",
                "member_count": 5
            },
            {
                "id": "team-2", 
                "name": "Frontend Team",
                "handle": "frontend",
                "description": "UI development",
                "member_count": 4
            }
        ]
        
        # Test that we can process teams data
        assert len(sample_teams) == 2
        assert all("name" in team for team in sample_teams)
        assert all("handle" in team for team in sample_teams)
    
    def test_teams_detailed_formatting(self):
        """Test detailed teams formatting with members"""
        sample_data = {
            "teams": [
                {
                    "id": "team-1",
                    "name": "DevOps Team",
                    "handle": "devops",
                    "description": "Infrastructure team"
                }
            ],
            "users": [
                {
                    "id": "user-1",
                    "name": "John Doe",
                    "email": "john@example.com",
                    "teams": ["team-1"]
                },
                {
                    "id": "user-2",
                    "name": "Jane Smith", 
                    "email": "jane@example.com",
                    "teams": ["team-1"]
                }
            ]
        }
        
        # Verify data structure
        assert "teams" in sample_data
        assert "users" in sample_data
        assert len(sample_data["teams"]) == 1
        assert len(sample_data["users"]) == 2
        
        # Verify relationships
        team_id = sample_data["teams"][0]["id"]
        team_members = [user for user in sample_data["users"] if team_id in user["teams"]]
        assert len(team_members) == 2
    
    def test_teams_json_formatting(self):
        """Test teams JSON formatting"""
        sample_teams = [
            {
                "id": "team-1",
                "name": "Security Team",
                "handle": "security"
            }
        ]
        
        json_output = json.dumps(sample_teams, indent=2)
        assert isinstance(json_output, str)
        
        # Should be valid JSON
        parsed = json.loads(json_output)
        assert len(parsed) == 1
        assert parsed[0]["name"] == "Security Team"


class TestTeamsFiltering:
    """Test team filtering functionality"""
    
    @pytest.mark.asyncio
    async def test_teams_by_name_filter(self):
        """Test filtering teams by name"""
        team_name = "Backend Team"
        
        with patch('datadog_mcp.utils.datadog_client.httpx.AsyncClient') as mock_client:
            mock_response = {
                "data": [
                    {
                        "id": "team-123",
                        "type": "teams",
                        "attributes": {
                            "name": "Backend Team",
                            "handle": "backend"
                        }
                    }
                ]
            }
            mock_client.return_value.__aenter__.return_value.get.return_value.json.return_value = mock_response
            mock_client.return_value.__aenter__.return_value.get.return_value.raise_for_status.return_value = None
            
            result = await datadog_client.fetch_teams(team_name=team_name)
            
            # Verify the request was made with proper filter
            call_args = mock_client.return_value.__aenter__.return_value.get.call_args
            assert call_args is not None
    
    @pytest.mark.asyncio
    async def test_teams_include_members_option(self):
        """Test include_members filtering option"""
        include_members = True
        
        with patch('datadog_mcp.utils.datadog_client.httpx.AsyncClient') as mock_client:
            mock_response = {
                "data": [
                    {
                        "id": "team-123",
                        "type": "teams",
                        "attributes": {"name": "Test Team"},
                        "relationships": {
                            "users": {"data": []}
                        }
                    }
                ],
                "included": []
            }
            mock_client.return_value.__aenter__.return_value.get.return_value.json.return_value = mock_response
            mock_client.return_value.__aenter__.return_value.get.return_value.raise_for_status.return_value = None
            
            result = await datadog_client.fetch_teams(include_members=include_members)
            
            # Verify the request was made
            mock_client.return_value.__aenter__.return_value.get.assert_called_once()


class TestTeamsValidation:
    """Test team input validation"""
    
    @pytest.mark.asyncio
    async def test_invalid_team_name_handling(self):
        """Test handling of invalid team names"""
        mock_request = MagicMock()
        mock_request.arguments = {
            "team_name": "",  # Empty team name
            "include_members": True
        }
        
        result = await get_teams.handle_call(mock_request)
        
        # Should handle gracefully (either error or validation message)
        assert isinstance(result, CallToolResult)
        if result.isError:
            assert len(result.content) > 0
    
    @pytest.mark.asyncio
    async def test_invalid_format_handling(self):
        """Test handling of invalid format options"""
        mock_request = MagicMock()
        mock_request.arguments = {
            "format": "invalid_format"
        }
        
        # Should handle gracefully
        try:
            result = await get_teams.handle_call(mock_request)
            assert isinstance(result, CallToolResult)
        except Exception:
            # If validation happens at tool level, that's also acceptable
            pass


class TestTeamsIntegration:
    """Test teams integration functionality"""
    
    @pytest.mark.asyncio
    async def test_teams_with_user_relationships(self):
        """Test teams data with proper user relationships"""
        mock_response = {
            "data": [
                {
                    "id": "team-1",
                    "type": "teams",
                    "attributes": {
                        "name": "Engineering",
                        "handle": "engineering"
                    },
                    "relationships": {
                        "users": {
                            "data": [
                                {"id": "user-1", "type": "users"},
                                {"id": "user-2", "type": "users"}
                            ]
                        }
                    }
                }
            ],
            "included": [
                {
                    "id": "user-1",
                    "type": "users",
                    "attributes": {
                        "name": "Developer One",
                        "email": "dev1@example.com"
                    }
                },
                {
                    "id": "user-2",
                    "type": "users", 
                    "attributes": {
                        "name": "Developer Two",
                        "email": "dev2@example.com"
                    }
                }
            ]
        }
        
        with patch('datadog_mcp.utils.datadog_client.httpx.AsyncClient') as mock_client:
            mock_client.return_value.__aenter__.return_value.get.return_value.json.return_value = mock_response
            mock_client.return_value.__aenter__.return_value.get.return_value.raise_for_status.return_value = None
            
            result = await datadog_client.fetch_teams(include_members=True)
            
            # Verify proper relationship processing
            assert isinstance(result, dict)
            assert "teams" in result
            assert "users" in result
            
            # Should have processed relationships correctly
            teams = result["teams"]
            users = result["users"]
            assert len(teams) == 1
            assert len(users) == 2


if __name__ == "__main__":
    pytest.main([__file__])