"""
测试 API 截断检测逻辑 —— JSON 参数校验、截断警告

模拟 main_agent.py 中 _call_openai_api 流式结束后对 finish_reason=="length"
的处理逻辑：验证 tool call 的 arguments 是否为合法 JSON。
"""
import json
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent))


def _simulate_truncation_check(tool_calls_list, finish_reason):
    """
    模拟 main_agent.py 中的截断检测逻辑。
    返回 (warning, invalid_names) 元组。
    """
    warning = ""
    invalid_tool_names = []

    if finish_reason == "length":
        warning = "API response was truncated"
        if tool_calls_list:
            for tc in tool_calls_list:
                args = tc.get("arguments", "")
                if isinstance(args, str):
                    try:
                        json.loads(args)
                    except json.JSONDecodeError:
                        invalid_tool_names.append(tc.get("name", "unknown"))
            if invalid_tool_names:
                warning += f" Tool call arguments incomplete ({', '.join(invalid_tool_names)})."
        warning += " Reduce content per request or increase max_tokens in config."

    return warning, invalid_tool_names


class TestTruncationJsonValidation:
    """截断场景的 JSON 参数校验"""

    def test_valid_json_not_reported(self):
        calls = [{"name": "run_shell", "arguments": '{"command": "ls"}'}]
        warning, invalid = _simulate_truncation_check(calls, "length")
        assert len(invalid) == 0
        assert "incomplete" not in warning

    def test_invalid_json_reported(self):
        calls = [{"name": "run_shell", "arguments": '{"command": "ls"'}]
        warning, invalid = _simulate_truncation_check(calls, "length")
        assert "run_shell" in invalid
        assert "incomplete" in warning

    def test_empty_arguments_reported(self):
        calls = [{"name": "run_shell", "arguments": ""}]
        warning, invalid = _simulate_truncation_check(calls, "length")
        assert "run_shell" in invalid

    def test_multiple_tools_some_invalid(self):
        calls = [
            {"name": "run_shell", "arguments": '{"command": "ls"}'},
            {"name": "run_shell", "arguments": '{"command": "cat f'},
        ]
        warning, invalid = _simulate_truncation_check(calls, "length")
        assert "run_shell" in invalid
        assert len(invalid) == 1

    def test_no_truncation_no_warning(self):
        calls = [{"name": "run_shell", "arguments": '{"command": "ls"}'}]
        warning, invalid = _simulate_truncation_check(calls, "stop")
        assert warning == ""

    def test_dict_arguments_skipped(self):
        calls = [{"name": "run_shell", "arguments": {"command": "ls"}}]
        warning, invalid = _simulate_truncation_check(calls, "length")
        assert len(invalid) == 0

    def test_truncated_very_long_json(self):
        args = '{"command": "' + "A" * 10000
        calls = [{"name": "run_shell", "arguments": args}]
        warning, invalid = _simulate_truncation_check(calls, "length")
        assert "run_shell" in invalid

    def test_valid_very_long_json(self):
        content = "print('hello world')" * 5000
        cmd = f"python3 -c \"{content}\""
        safe_cmd = json.dumps(cmd)
        args = '{"command": ' + safe_cmd + '}'
        json.loads(args)
        calls = [{"name": "run_shell", "arguments": args}]
        warning, invalid = _simulate_truncation_check(calls, "length")
        assert len(invalid) == 0

    def test_no_tool_calls_no_warning(self):
        warning, invalid = _simulate_truncation_check([], "length")
        assert "incomplete" not in warning

    def test_unicode_in_arguments(self):
        args = '{"command": "echo 你好世界"}'
        calls = [{"name": "run_shell", "arguments": args}]
        warning, invalid = _simulate_truncation_check(calls, "length")
        assert len(invalid) == 0


class TestTruncationMessageFormat:
    """截断警告消息格式"""

    def test_warning_contains_reduce_suggestion(self):
        warning, _ = _simulate_truncation_check(
            [{"name": "run_shell", "arguments": "{"}], "length"
        )
        assert "Reduce" in warning
        assert "max_tokens" in warning

    def test_warning_with_tool_name(self):
        warning, _ = _simulate_truncation_check(
            [{"name": "fetch_url", "arguments": '{"url": "http'}], "length"
        )
        assert "fetch_url" in warning

    def test_finish_reason_stop_no_warning(self):
        warning, _ = _simulate_truncation_check(
            [{"name": "run_shell", "arguments": "{"}], "stop"
        )
        assert warning == ""

    def test_finish_reason_tool_calls_no_warning(self):
        warning, _ = _simulate_truncation_check(
            [{"name": "run_shell", "arguments": '{"command": "ls"}'}],
            "tool_calls",
        )
        assert warning == ""
