# -*- coding: utf-8 -*-
"""CI RetryCommand 测试（Phase 8 Tier 2）

借鉴 zhikuncode RetryCommand：
- /retry 命令把上一条 user 消息重新注入会话
- 支持 string 和 list[dict] 两种 content 格式
- 返回特殊标记 "injected"，由主循环将其作为新的 prompt
"""
from unittest.mock import MagicMock

import pytest

from abyss.commands.retry import handle_retry, find_last_user_message, extract_user_text


class TestFindLastUserMessage:
    """find_last_user_message 测试"""

    def test_finds_last_user_message(self):
        """标准 string content"""
        messages = [
            {"role": "system", "content": "system"},
            {"role": "user", "content": "first question"},
            {"role": "assistant", "content": "answer"},
            {"role": "user", "content": "second question"},
            {"role": "assistant", "content": "answer 2"},
        ]
        msg = find_last_user_message(messages)
        assert msg is not None
        assert msg["content"] == "second question"

    def test_returns_none_when_no_user_messages(self):
        """无 user 消息时返回 None"""
        messages = [
            {"role": "system", "content": "system"},
            {"role": "assistant", "content": "hi"},
        ]
        assert find_last_user_message(messages) is None

    def test_returns_none_for_empty_messages(self):
        """空 messages"""
        assert find_last_user_message([]) is None

    def test_skips_tool_role_messages(self):
        """不被 tool 消息干扰"""
        messages = [
            {"role": "user", "content": "real question"},
            {"role": "assistant", "content": None, "tool_calls": [{"id": "1", "function": {"name": "x"}}]},
            {"role": "tool", "content": "tool result", "tool_call_id": "1"},
        ]
        msg = find_last_user_message(messages)
        assert msg is not None
        assert msg["content"] == "real question"

    def test_handles_missing_role_field(self):
        """缺少 role 字段的消息跳过"""
        messages = [
            {"content": "no role"},
            {"role": "user", "content": "valid"},
        ]
        msg = find_last_user_message(messages)
        assert msg is not None
        assert msg["content"] == "valid"


class TestExtractUserText:
    """extract_user_text 测试"""

    def test_extracts_string_content(self):
        """string content 直接返回"""
        msg = {"role": "user", "content": "hello world"}
        assert extract_user_text(msg) == "hello world"

    def test_extracts_list_content_with_text_blocks(self):
        """list[dict] 格式合并 text blocks"""
        msg = {
            "role": "user",
            "content": [
                {"type": "text", "text": "first "},
                {"type": "text", "text": "second"},
            ],
        }
        assert extract_user_text(msg) == "first second"

    def test_extracts_list_content_skips_non_text_blocks(self):
        """list 格式跳过非 text 类型的 block"""
        msg = {
            "role": "user",
            "content": [
                {"type": "image_url", "image_url": {"url": "..."}},
                {"type": "text", "text": "actual text"},
            ],
        }
        assert extract_user_text(msg) == "actual text"

    def test_returns_empty_for_none_content(self):
        """content 为 None"""
        msg = {"role": "user", "content": None}
        assert extract_user_text(msg) == ""

    def test_returns_empty_for_missing_content(self):
        """缺少 content 字段"""
        msg = {"role": "user"}
        assert extract_user_text(msg) == ""

    def test_handles_non_dict_blocks_in_list(self):
        """list 中混入非 dict 元素"""
        msg = {
            "role": "user",
            "content": ["invalid string", {"type": "text", "text": "valid"}],
        }
        assert extract_user_text(msg) == "valid"


class TestHandleRetry:
    """handle_retry 测试"""

    def test_returns_injected_marker_when_user_message_exists(self):
        """有 user 消息时返回 'injected'"""
        session = MagicMock()
        session.messages = [
            {"role": "system", "content": "sys"},
            {"role": "user", "content": "test question"},
            {"role": "assistant", "content": "answer"},
        ]
        result = handle_retry(session)
        assert result == "injected"

    def test_adds_user_message_to_session(self):
        """retry 会把上一条 user 消息注入为新消息"""
        session = MagicMock()
        session.messages = [
            {"role": "system", "content": "sys"},
            {"role": "user", "content": "test question"},
            {"role": "assistant", "content": "answer"},
        ]
        handle_retry(session)
        # 验证 add_user 被调用
        session.add_user.assert_called_once()
        args = session.add_user.call_args[0]
        assert args[0] == "test question"

    def test_returns_false_when_no_user_messages(self):
        """无 user 消息时返回 False"""
        session = MagicMock()
        session.messages = [
            {"role": "system", "content": "sys"},
            {"role": "assistant", "content": "hi"},
        ]
        result = handle_retry(session)
        assert result is False
        session.add_user.assert_not_called()

    def test_returns_false_for_empty_session(self):
        """空 session"""
        session = MagicMock()
        session.messages = []
        result = handle_retry(session)
        assert result is False

    def test_uses_last_user_message_when_multiple(self):
        """多条 user 时用最后一条"""
        session = MagicMock()
        session.messages = [
            {"role": "system", "content": "sys"},
            {"role": "user", "content": "first"},
            {"role": "assistant", "content": "ans1"},
            {"role": "user", "content": "second"},
            {"role": "assistant", "content": "ans2"},
        ]
        handle_retry(session)
        args = session.add_user.call_args[0]
        assert args[0] == "second"

    def test_handles_list_content_user_message(self):
        """list 格式 content"""
        session = MagicMock()
        session.messages = [
            {"role": "system", "content": "sys"},
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "list "},
                    {"type": "text", "text": "question"},
                ],
            },
            {"role": "assistant", "content": "ans"},
        ]
        result = handle_retry(session)
        assert result == "injected"
        args = session.add_user.call_args[0]
        assert args[0] == "list question"
