"""
Tests for common Jira Pydantic models.

Tests for JiraUser, JiraStatusCategory, JiraStatus, JiraIssueType,
JiraPriority, and JiraChangelog models.
"""

import json
from datetime import datetime, timezone

from mcp_atlassian.models.constants import (
    EMPTY_STRING,
    JIRA_DEFAULT_ID,
    UNKNOWN,
)
from mcp_atlassian.models.jira import (
    JiraIssueType,
    JiraPriority,
    JiraStatus,
    JiraStatusCategory,
    JiraUser,
)
from mcp_atlassian.models.jira.common import JiraChangelog


class TestJiraUser:
    """Tests for the JiraUser model."""

    def test_from_api_response_with_valid_data(self):
        """Test creating a JiraUser from valid API data."""
        user_data = {
            "accountId": "user123",
            "displayName": "Test User",
            "emailAddress": "test@example.com",
            "active": True,
            "avatarUrls": {
                "48x48": "https://example.com/avatar.png",
                "24x24": "https://example.com/avatar-small.png",
            },
            "timeZone": "UTC",
        }
        user = JiraUser.from_api_response(user_data)
        assert user.account_id == "user123"
        assert user.display_name == "Test User"
        assert user.email == "test@example.com"
        assert user.active is True
        assert user.avatar_url == "https://example.com/avatar.png"
        assert user.time_zone == "UTC"

    def test_from_api_response_with_empty_data(self):
        """Test creating a JiraUser from empty data."""
        user = JiraUser.from_api_response({})
        assert user.account_id is None
        assert user.display_name == "Unassigned"
        assert user.email is None
        assert user.active is True
        assert user.avatar_url is None
        assert user.time_zone is None

    def test_from_api_response_with_none_data(self):
        """Test creating a JiraUser from None data."""
        user = JiraUser.from_api_response(None)
        assert user.account_id is None
        assert user.display_name == "Unassigned"
        assert user.email is None
        assert user.active is True
        assert user.avatar_url is None
        assert user.time_zone is None

    def test_to_simplified_dict(self):
        """Test converting JiraUser to a simplified dictionary."""
        user = JiraUser(
            account_id="user123",
            display_name="Test User",
            email="test@example.com",
            active=True,
            avatar_url="https://example.com/avatar.png",
            time_zone="UTC",
        )
        simplified = user.to_simplified_dict()
        assert isinstance(simplified, dict)
        assert simplified["display_name"] == "Test User"
        assert simplified["email"] == "test@example.com"
        assert simplified["avatar_url"] == "https://example.com/avatar.png"
        assert "account_id" not in simplified
        assert "time_zone" not in simplified

    def test_from_api_response_server_dc_with_name_and_key(self):
        """Test JiraUser captures username and key from Server/DC API response."""
        user_data = {
            "name": "jdoe",
            "key": "JIRAUSER123",
            "displayName": "John Doe",
            "emailAddress": "jdoe@example.com",
            "active": True,
            "avatarUrls": {"48x48": "https://example.com/avatar.png"},
        }
        user = JiraUser.from_api_response(user_data)
        assert user.username == "jdoe"
        assert user.user_key == "JIRAUSER123"
        assert user.display_name == "John Doe"

    def test_from_api_response_cloud_no_name_key(self):
        """Test JiraUser handles Cloud response without name/key fields."""
        user_data = {
            "accountId": "abc123",
            "displayName": "John Doe",
            "emailAddress": "jdoe@example.com",
            "active": True,
        }
        user = JiraUser.from_api_response(user_data)
        assert user.username is None
        assert user.user_key is None
        assert user.display_name == "John Doe"
        assert user.account_id == "abc123"

    def test_from_api_response_server_dc_name_only(self):
        """Test JiraUser handles Server/DC response with name but no key."""
        user_data = {
            "name": "jdoe",
            "displayName": "John Doe",
            "active": True,
        }
        user = JiraUser.from_api_response(user_data)
        assert user.username == "jdoe"
        assert user.user_key is None
        assert user.display_name == "John Doe"

    def test_to_simplified_dict_server_dc_uses_username(self):
        """Test to_simplified_dict returns login username, not display name."""
        user = JiraUser(
            display_name="John Doe",
            username="jdoe",
            user_key="JIRAUSER123",
            email="jdoe@example.com",
        )
        simplified = user.to_simplified_dict()
        assert simplified["name"] == "jdoe"
        assert simplified["display_name"] == "John Doe"
        assert simplified["key"] == "JIRAUSER123"

    def test_to_simplified_dict_cloud_falls_back_to_display_name(self):
        """Test to_simplified_dict falls back to display_name when no username."""
        user = JiraUser(
            account_id="abc123",
            display_name="John Doe",
            email="jdoe@example.com",
        )
        simplified = user.to_simplified_dict()
        assert simplified["name"] == "John Doe"
        assert simplified["display_name"] == "John Doe"
        assert "key" not in simplified


class TestJiraStatusCategory:
    """Tests for the JiraStatusCategory model."""

    def test_from_api_response_with_valid_data(self):
        """Test creating a JiraStatusCategory from valid API data."""
        data = {
            "id": 4,
            "key": "indeterminate",
            "name": "In Progress",
            "colorName": "yellow",
        }
        category = JiraStatusCategory.from_api_response(data)
        assert category.id == 4
        assert category.key == "indeterminate"
        assert category.name == "In Progress"
        assert category.color_name == "yellow"

    def test_from_api_response_with_empty_data(self):
        """Test creating a JiraStatusCategory from empty data."""
        category = JiraStatusCategory.from_api_response({})
        assert category.id == 0
        assert category.key == EMPTY_STRING
        assert category.name == UNKNOWN
        assert category.color_name == EMPTY_STRING


class TestJiraStatus:
    """Tests for the JiraStatus model."""

    def test_from_api_response_with_valid_data(self):
        """Test creating a JiraStatus from valid API data."""
        data = {
            "id": "10000",
            "name": "In Progress",
            "description": "Work is in progress",
            "iconUrl": "https://example.com/icon.png",
            "statusCategory": {
                "id": 4,
                "key": "indeterminate",
                "name": "In Progress",
                "colorName": "yellow",
            },
        }
        status = JiraStatus.from_api_response(data)
        assert status.id == "10000"
        assert status.name == "In Progress"
        assert status.description == "Work is in progress"
        assert status.icon_url == "https://example.com/icon.png"
        assert status.category is not None
        assert status.category.id == 4
        assert status.category.name == "In Progress"
        assert status.category.color_name == "yellow"

    def test_from_api_response_with_empty_data(self):
        """Test creating a JiraStatus from empty data."""
        status = JiraStatus.from_api_response({})
        assert status.id == JIRA_DEFAULT_ID
        assert status.name == UNKNOWN
        assert status.description is None
        assert status.icon_url is None
        assert status.category is None

    def test_to_simplified_dict(self):
        """Test converting JiraStatus to a simplified dictionary."""
        status = JiraStatus(
            id="10000",
            name="In Progress",
            description="Work is in progress",
            icon_url="https://example.com/icon.png",
            category=JiraStatusCategory(
                id=4, key="indeterminate", name="In Progress", color_name="yellow"
            ),
        )
        simplified = status.to_simplified_dict()
        assert isinstance(simplified, dict)
        assert simplified["name"] == "In Progress"
        assert "category" in simplified
        assert simplified["category"] == "In Progress"
        assert "color" in simplified
        assert simplified["color"] == "yellow"
        assert "description" not in simplified


class TestJiraIssueType:
    """Tests for the JiraIssueType model."""

    def test_from_api_response_with_valid_data(self):
        """Test creating a JiraIssueType from valid API data."""
        data = {
            "id": "10000",
            "name": "Task",
            "description": "A task that needs to be done.",
            "iconUrl": "https://example.com/task-icon.png",
        }
        issue_type = JiraIssueType.from_api_response(data)
        assert issue_type.id == "10000"
        assert issue_type.name == "Task"
        assert issue_type.description == "A task that needs to be done."
        assert issue_type.icon_url == "https://example.com/task-icon.png"

    def test_from_api_response_with_empty_data(self):
        """Test creating a JiraIssueType from empty data."""
        issue_type = JiraIssueType.from_api_response({})
        assert issue_type.id == JIRA_DEFAULT_ID
        assert issue_type.name == UNKNOWN
        assert issue_type.description is None
        assert issue_type.icon_url is None

    def test_to_simplified_dict(self):
        """Test converting JiraIssueType to a simplified dictionary."""
        issue_type = JiraIssueType(
            id="10000",
            name="Task",
            description="A task that needs to be done.",
            icon_url="https://example.com/task-icon.png",
        )
        simplified = issue_type.to_simplified_dict()
        assert isinstance(simplified, dict)
        assert simplified["name"] == "Task"
        assert "id" not in simplified
        assert "description" not in simplified
        assert "icon_url" not in simplified


class TestJiraPriority:
    """Tests for the JiraPriority model."""

    def test_from_api_response_with_valid_data(self):
        """Test creating a JiraPriority from valid API data."""
        data = {
            "id": "3",
            "name": "Medium",
            "description": "Medium priority",
            "iconUrl": "https://example.com/medium-priority.png",
        }
        priority = JiraPriority.from_api_response(data)
        assert priority.id == "3"
        assert priority.name == "Medium"
        assert priority.description == "Medium priority"
        assert priority.icon_url == "https://example.com/medium-priority.png"

    def test_from_api_response_with_empty_data(self):
        """Test creating a JiraPriority from empty data."""
        priority = JiraPriority.from_api_response({})
        assert priority.id == JIRA_DEFAULT_ID
        assert priority.name == "None"  # Default for priority is 'None'
        assert priority.description is None
        assert priority.icon_url is None

    def test_to_simplified_dict(self):
        """Test converting JiraPriority to a simplified dictionary."""
        priority = JiraPriority(
            id="3",
            name="Medium",
            description="Medium priority",
            icon_url="https://example.com/medium-priority.png",
        )
        simplified = priority.to_simplified_dict()
        assert isinstance(simplified, dict)
        assert simplified["name"] == "Medium"
        assert "id" not in simplified
        assert "description" not in simplified
        assert "icon_url" not in simplified


class TestJiraChangelog:
    """Tests for JiraChangelog datetime serialization (fixes #749)."""

    def test_created_datetime_serialization(self):
        """Test that datetime created field serializes to JSON properly."""
        changelog = JiraChangelog(
            id="12345",
            created=datetime(2024, 1, 15, 10, 30, 0, tzinfo=timezone.utc),
            items=[],
        )

        # model_dump should serialize datetime to ISO string
        dumped = changelog.model_dump(mode="json")
        assert isinstance(dumped["created"], str)
        assert "2024-01-15" in dumped["created"]

        # to_simplified_dict should also work
        simplified = changelog.to_simplified_dict()
        assert isinstance(simplified["created"], str)

        # Final json.dumps should not raise
        json_str = json.dumps(simplified)
        assert "2024-01-15" in json_str

    def test_from_api_response_with_changelog(self):
        """Test JiraChangelog.from_api_response handles dates correctly."""
        data = {
            "id": "100",
            "created": "2024-01-15T10:30:00.000+0000",
            "author": {"displayName": "Test User"},
            "items": [{"field": "status", "fromString": "Open", "toString": "Done"}],
        }

        changelog = JiraChangelog.from_api_response(data)
        assert isinstance(changelog.created, datetime)

        # Should serialize cleanly to JSON
        simplified = changelog.to_simplified_dict()
        json_str = json.dumps(simplified)
        assert "2024-01-15" in json_str
