"""Tests for the /resume command functionality."""

from unittest.mock import MagicMock, patch
from uuid import UUID
import pytest
from prompt_toolkit.input.defaults import create_pipe_input
from prompt_toolkit.output.defaults import DummyOutput

from openhands.sdk.conversation.state import ConversationExecutionStatus
from openhands_cli.user_actions import UserConfirmation


# ---------- Fixtures & helpers ----------

@pytest.fixture
def mock_agent():
    """Mock agent for verification."""
    return MagicMock()


@pytest.fixture
def mock_conversation():
    """Mock conversation with default settings."""
    conv = MagicMock()
    conv.id = UUID('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa')
    return conv


@pytest.fixture
def mock_runner():
    """Mock conversation runner."""
    return MagicMock()


def run_resume_command_test(commands, agent_status=None, expect_runner_created=True):
    """Helper function to run resume command tests with common setup."""
    with patch('openhands_cli.agent_chat.exit_session_confirmation') as mock_exit_confirm, \
         patch('openhands_cli.agent_chat.get_session_prompter') as mock_get_session_prompter, \
         patch('openhands_cli.agent_chat.setup_conversation') as mock_setup_conversation, \
         patch('openhands_cli.agent_chat.verify_agent_exists_or_setup_agent') as mock_verify_agent, \
         patch('openhands_cli.agent_chat.ConversationRunner') as mock_runner_cls:

        # Auto-accept the exit prompt to avoid interactive UI
        mock_exit_confirm.return_value = UserConfirmation.ACCEPT

        # Mock agent verification to succeed
        mock_agent = MagicMock()
        mock_verify_agent.return_value = mock_agent

        # Mock conversation setup
        conv = MagicMock()
        conv.id = UUID('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa')
        if agent_status:
            conv.state.execution_status = agent_status
        mock_setup_conversation.return_value = conv

        # Mock runner
        runner = MagicMock()
        runner.conversation = conv
        mock_runner_cls.return_value = runner

        # Real session fed by a pipe
        from openhands_cli.user_actions.utils import get_session_prompter as real_get_session_prompter
        with create_pipe_input() as pipe:
            output = DummyOutput()
            session = real_get_session_prompter(input=pipe, output=output)
            mock_get_session_prompter.return_value = session

            from openhands_cli.agent_chat import run_cli_entry

            # Send commands
            for ch in commands:
                pipe.send_text(ch)

            # Capture printed output
            with patch('openhands_cli.agent_chat.print_formatted_text') as mock_print:
                run_cli_entry(None)

            return mock_runner_cls, runner, mock_print


# ---------- Warning tests (parametrized) ----------

@pytest.mark.parametrize(
    "commands,expected_warning,expect_runner_created",
    [
        # No active conversation - /resume immediately
        ("/resume\r/exit\r", "No active conversation running", False),
        # Conversation exists but not in paused state - send message first, then /resume
        ("hello\r/resume\r/exit\r", "No paused conversation to resume", True),
    ],
)
def test_resume_command_warnings(commands, expected_warning, expect_runner_created):
    """Test /resume command shows appropriate warnings."""
    # Set agent status to FINISHED for the "conversation exists but not paused" test
    agent_status = ConversationExecutionStatus.FINISHED if expect_runner_created else None

    mock_runner_cls, runner, mock_print = run_resume_command_test(
        commands, agent_status=agent_status, expect_runner_created=expect_runner_created
    )

    # Verify warning message was printed
    warning_calls = [call for call in mock_print.call_args_list
                    if expected_warning in str(call)]
    assert len(warning_calls) > 0, f"Expected warning about {expected_warning}"

    # Verify runner creation expectation
    if expect_runner_created:
        assert mock_runner_cls.call_count == 1
        runner.process_message.assert_called()
    else:
        assert mock_runner_cls.call_count == 0


# ---------- Successful resume tests (parametrized) ----------

@pytest.mark.parametrize(
    "agent_status",
    [
        ConversationExecutionStatus.PAUSED,
        ConversationExecutionStatus.WAITING_FOR_CONFIRMATION,
    ],
)
def test_resume_command_successful_resume(agent_status):
    """Test /resume command successfully resumes paused/waiting conversations."""
    commands = "hello\r/resume\r/exit\r"

    mock_runner_cls, runner, mock_print = run_resume_command_test(
        commands, agent_status=agent_status, expect_runner_created=True
    )

    # Verify runner was created and process_message was called
    assert mock_runner_cls.call_count == 1

    # Verify process_message was called twice: once with the initial message, once with None for resume
    assert runner.process_message.call_count == 2

    # Check the calls to process_message
    calls = runner.process_message.call_args_list

    # First call should have a message (the "hello" message)
    first_call_args = calls[0][0]
    assert first_call_args[0] is not None, "First call should have a message"

    # Second call should have None (the /resume command)
    second_call_args = calls[1][0]
    assert second_call_args[0] is None, "Second call should have None message for resume"
