"""Tests for create_issue.py module."""

from pathlib import Path
from unittest.mock import Mock, patch

import pytest
import typer

from jps_jira_utils.create_issue import (
    create_issue,
    get_current_user,
    get_issue_types,
    main,
    prompt_for_issue_type,
)


class TestGetIssueTypes:
    """Tests for get_issue_types function."""

    @patch("jps_jira_utils.create_issue.setup_logging")
    def test_get_issue_types_success(self, mock_logging):
        """Test successful retrieval of issue types."""
        mock_logger = Mock()
        mock_logging.return_value = mock_logger

        session = Mock()
        response = Mock()
        response.ok = True
        response.json.return_value = {
            "projects": [
                {
                    "issuetypes": [
                        {"name": "Task", "id": "10001"},
                        {"name": "Bug", "id": "10002"},
                    ]
                }
            ]
        }
        session.get.return_value = response

        result = get_issue_types(session, "https://jira.example.com", "JPS", mock_logger)

        assert len(result) == 2
        assert result[0]["name"] == "Task"
        assert result[1]["name"] == "Bug"

    @patch("jps_jira_utils.create_issue.setup_logging")
    def test_get_issue_types_project_not_found(self, mock_logging):
        """Test when project is not found."""
        mock_logger = Mock()
        mock_logging.return_value = mock_logger

        session = Mock()
        response = Mock()
        response.ok = True
        response.json.return_value = {"projects": []}
        session.get.return_value = response

        with pytest.raises(typer.Exit):
            get_issue_types(session, "https://jira.example.com", "INVALID", mock_logger)

    @patch("jps_jira_utils.create_issue.setup_logging")
    def test_get_issue_types_api_error(self, mock_logging):
        """Test when API returns error."""
        mock_logger = Mock()
        mock_logging.return_value = mock_logger

        session = Mock()
        response = Mock()
        response.ok = False
        response.status_code = 403
        response.text = "Forbidden"
        session.get.return_value = response

        with pytest.raises(typer.Exit):
            get_issue_types(session, "https://jira.example.com", "JPS", mock_logger)


class TestGetCurrentUser:
    """Tests for get_current_user function."""

    @patch("jps_jira_utils.create_issue.setup_logging")
    def test_get_current_user_success(self, mock_logging):
        """Test successful retrieval of current user."""
        mock_logger = Mock()
        mock_logging.return_value = mock_logger

        session = Mock()
        response = Mock()
        response.ok = True
        response.json.return_value = {
            "accountId": "account-id-123",
            "emailAddress": "user@example.com",
            "displayName": "Test User"
        }
        session.get.return_value = response

        result = get_current_user(session, "https://jira.example.com", mock_logger)

        assert result["accountId"] == "account-id-123"
        assert result["emailAddress"] == "user@example.com"

    @patch("jps_jira_utils.create_issue.setup_logging")
    def test_get_current_user_api_error(self, mock_logging):
        """Test when API returns error."""
        mock_logger = Mock()
        mock_logging.return_value = mock_logger

        session = Mock()
        response = Mock()
        response.ok = False
        response.status_code = 401
        response.text = "Unauthorized"
        session.get.return_value = response

        with pytest.raises(typer.Exit):
            get_current_user(session, "https://jira.example.com", mock_logger)


class TestPromptForIssueType:
    """Tests for prompt_for_issue_type function."""

    def test_prompt_numeric_selection(self, monkeypatch):
        """Test selecting issue type by number."""
        issue_types = [
            {"name": "Task", "id": "10001"},
            {"name": "Bug", "id": "10002"},
        ]
        
        monkeypatch.setattr("typer.prompt", lambda *args, **kwargs: "1")
        
        result = prompt_for_issue_type(issue_types)
        assert result == "Task"

    def test_prompt_name_selection(self, monkeypatch):
        """Test selecting issue type by name."""
        issue_types = [
            {"name": "Task", "id": "10001"},
            {"name": "Bug", "id": "10002"},
        ]
        
        monkeypatch.setattr("typer.prompt", lambda *args, **kwargs: "bug")
        
        result = prompt_for_issue_type(issue_types)
        assert result == "Bug"

    def test_prompt_empty_issue_types(self):
        """Test with no available issue types."""
        with pytest.raises(typer.Exit):
            prompt_for_issue_type([])

    def test_prompt_invalid_then_valid(self, monkeypatch):
        """Test invalid selection followed by valid one."""
        issue_types = [
            {"name": "Task", "id": "10001"},
            {"name": "Bug", "id": "10002"},
        ]
        
        inputs = iter(["invalid", "99", "2"])
        monkeypatch.setattr("typer.prompt", lambda *args, **kwargs: next(inputs))
        
        result = prompt_for_issue_type(issue_types)
        assert result == "Bug"


class TestCreateIssue:
    """Tests for create_issue function."""

    @patch("jps_jira_utils.create_issue.setup_logging")
    def test_create_issue_success(self, mock_logging):
        """Test successful issue creation."""
        mock_logger = Mock()
        mock_logging.return_value = mock_logger

        session = Mock()
        response = Mock()
        response.ok = True
        response.json.return_value = {"key": "JPS-123"}
        session.post.return_value = response

        issue_key, issue_url = create_issue(
            session,
            "https://jira.example.com",
            "JPS",
            "Task",
            "Test issue",
            "Test description",
            "account-id-123",
            mock_logger,
        )

        assert issue_key == "JPS-123"
        assert issue_url == "https://jira.example.com/browse/JPS-123"
        
        # Verify reporter field is included in payload
        call_args = session.post.call_args
        payload = call_args.kwargs["json"]
        assert "reporter" in payload["fields"]
        assert payload["fields"]["reporter"]["accountId"] == "account-id-123"

    @patch("jps_jira_utils.create_issue.setup_logging")
    def test_create_issue_without_description(self, mock_logging):
        """Test creating issue without description."""
        mock_logger = Mock()
        mock_logging.return_value = mock_logger

        session = Mock()
        response = Mock()
        response.ok = True
        response.json.return_value = {"key": "JPS-124"}
        session.post.return_value = response

        issue_key, issue_url = create_issue(
            session,
            "https://jira.example.com",
            "JPS",
            "Bug",
            "Test bug",
            None,
            "account-id-456",
            mock_logger,
        )

        assert issue_key == "JPS-124"
        # Verify description field was not included in payload
        call_args = session.post.call_args
        payload = call_args.kwargs["json"]
        assert "description" not in payload["fields"]

    @patch("jps_jira_utils.create_issue.setup_logging")
    def test_create_issue_api_error(self, mock_logging):
        """Test when issue creation fails."""
        mock_logger = Mock()
        mock_logging.return_value = mock_logger

        session = Mock()
        response = Mock()
        response.ok = False
        response.status_code = 400
        response.text = "Bad Request"
        session.post.return_value = response

        with pytest.raises(typer.Exit):
            create_issue(
                session,
                "https://jira.example.com",
                "JPS",
                "Task",
                "Test issue",
                "Description",
                "account-id-789",
                mock_logger,
            )


class TestMainIntegration:
    """Integration tests for main function."""

    @patch("jps_jira_utils.create_issue.setup_logging")
    @patch("jps_jira_utils.create_issue.load_jira_env")
    @patch("jps_jira_utils.create_issue.requests.Session")
    @patch("jps_jira_utils.create_issue.get_current_user")
    def test_main_with_all_options(self, mock_get_user, mock_session, mock_env, mock_logging, monkeypatch):
        """Test main with all options provided."""
        # Setup mocks
        mock_env.return_value = ("https://jira.example.com", "user@example.com", "token")
        mock_logger = Mock()
        mock_logging.return_value = mock_logger
        
        # Mock get_current_user
        mock_get_user.return_value = {
            "accountId": "account-id-123",
            "emailAddress": "user@example.com",
            "displayName": "Test User"
        }

        session = Mock()
        
        # Mock get_issue_types response
        get_response = Mock()
        get_response.ok = True
        get_response.json.return_value = {
            "projects": [
                {"issuetypes": [{"name": "Task", "id": "10001"}]}
            ]
        }
        
        # Mock create_issue response
        post_response = Mock()
        post_response.ok = True
        post_response.json.return_value = {"key": "JPS-123"}
        
        session.get.return_value = get_response
        session.post.return_value = post_response
        mock_session.return_value = session

        # Mock confirmation
        monkeypatch.setattr("typer.confirm", lambda *args, **kwargs: True)

        # Run main
        main("JPS", "Test issue", "Test description", "Task", None, None, None)

        # Verify issue was created
        assert session.post.called

    @patch("jps_jira_utils.create_issue.setup_logging")
    @patch("jps_jira_utils.create_issue.load_jira_env")
    @patch("jps_jira_utils.create_issue.requests.Session")
    @patch("jps_jira_utils.create_issue.get_current_user")
    def test_main_with_prompts(self, mock_get_user, mock_session, mock_env, mock_logging, monkeypatch):
        """Test main with interactive prompts."""
        # Setup mocks
        mock_env.return_value = ("https://jira.example.com", "user@example.com", "token")
        mock_logger = Mock()
        mock_logging.return_value = mock_logger
        
        # Mock get_current_user
        mock_get_user.return_value = {
            "accountId": "account-id-456",
            "emailAddress": "user@example.com"
        }

        session = Mock()
        
        # Mock get_issue_types response
        get_response = Mock()
        get_response.ok = True
        get_response.json.return_value = {
            "projects": [
                {"issuetypes": [{"name": "Task", "id": "10001"}]}
            ]
        }
        
        # Mock create_issue response
        post_response = Mock()
        post_response.ok = True
        post_response.json.return_value = {"key": "JPS-124"}
        
        session.get.return_value = get_response
        session.post.return_value = post_response
        mock_session.return_value = session

        # Mock prompts
        prompts = {
            "Select issue type (number or name)": "1",
            "Enter issue summary (Title)": "Prompted summary",
            "Enter description": "Prompted description",
        }
        
        def mock_prompt(text, **kwargs):
            return prompts.get(text, kwargs.get("default", ""))
        
        monkeypatch.setattr("typer.prompt", mock_prompt)
        
        # Mock confirms - first for description, second for final confirmation
        confirms = iter([True, True])
        monkeypatch.setattr("typer.confirm", lambda *args, **kwargs: next(confirms))

        # Run main without options
        main("JPS", None, None, None, None, None, None)

        # Verify issue was created
        assert session.post.called

    @patch("jps_jira_utils.create_issue.setup_logging")
    @patch("jps_jira_utils.create_issue.load_jira_env")
    @patch("jps_jira_utils.create_issue.requests.Session")
    @patch("jps_jira_utils.create_issue.get_current_user")
    def test_main_user_cancels(self, mock_get_user, mock_session, mock_env, mock_logging, monkeypatch):
        """Test when user cancels at final confirmation."""
        # Setup mocks
        mock_env.return_value = ("https://jira.example.com", "user@example.com", "token")
        mock_logger = Mock()
        mock_logging.return_value = mock_logger
        
        # Mock get_current_user
        mock_get_user.return_value = {
            "accountId": "account-id-789",
            "emailAddress": "user@example.com"
        }

        session = Mock()
        get_response = Mock()
        get_response.ok = True
        get_response.json.return_value = {
            "projects": [
                {"issuetypes": [{"name": "Task", "id": "10001"}]}
            ]
        }
        session.get.return_value = get_response
        mock_session.return_value = session

        # Mock prompts
        monkeypatch.setattr("typer.prompt", lambda *args, **kwargs: "Test")
        
        # User says no to description, then cancels final confirmation
        confirms = iter([False, False])
        monkeypatch.setattr("typer.confirm", lambda *args, **kwargs: next(confirms))

        # Should exit without error
        with pytest.raises(typer.Exit) as exc_info:
            main("JPS", "Test", None, "Task", None, None, None)
        
        assert exc_info.value.exit_code == 0
        # Verify issue was not created
        assert not session.post.called
