"""
测试 SessionMessage 结构化字段持久化 —— tool_calls / tool_call_id / reasoning_content
"""
import sys
import tempfile
import asyncio
from pathlib import Path

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

import pytest
from aacode.utils.session_manager import SessionManager, SessionMessage


@pytest.fixture
def session_manager():
    with tempfile.TemporaryDirectory() as td:
        sm = SessionManager(Path(td))
        yield sm


class TestSessionMessageFields:
    """SessionMessage 数据类新字段"""

    def test_tool_calls_field(self):
        msg = SessionMessage(
            role="assistant", content="test", timestamp=0,
            tool_calls=[{"name": "run_shell", "arguments": '{"cmd":"ls"}'}]
        )
        assert msg.tool_calls == [{"name": "run_shell", "arguments": '{"cmd":"ls"}'}]

    def test_tool_call_id_field(self):
        msg = SessionMessage(
            role="tool", content="result", timestamp=0,
            tool_call_id="call_abc123"
        )
        assert msg.tool_call_id == "call_abc123"

    def test_reasoning_content_field(self):
        msg = SessionMessage(
            role="assistant", content="text", timestamp=0,
            reasoning_content="用户想看文件内容"
        )
        assert msg.reasoning_content == "用户想看文件内容"

    def test_all_fields_optional(self):
        msg = SessionMessage(role="user", content="hello", timestamp=0)
        assert msg.tool_calls is None
        assert msg.tool_call_id is None
        assert msg.reasoning_content is None


class TestAddMessageWithStructuredFields:
    """add_message 传递结构化字段"""

    @pytest.mark.asyncio
    async def test_add_assistant_with_tool_calls(self, session_manager):
        sm = session_manager
        sid = await sm.create_session("test task")
        result = await sm.add_message(
            "assistant", "thought",
            tool_calls=[{"name": "run_shell", "arguments": '{"command":"ls"}'}],
            reasoning_content="thinking...",
        )
        assert result is True
        msgs = await sm.get_messages(include_system=False)
        last = msgs[-1]
        assert last["role"] == "assistant"
        assert last["tool_calls"] == [{"name": "run_shell", "arguments": '{"command":"ls"}'}]
        assert last["reasoning_content"] == "thinking..."

    @pytest.mark.asyncio
    async def test_add_tool_message_with_id(self, session_manager):
        sm = session_manager
        sid = await sm.create_session("test task")
        await sm.add_message("tool", "ls output", tool_call_id="call_xyz")
        msgs = await sm.get_messages(include_system=False)
        last = msgs[-1]
        assert last["role"] == "tool"
        assert last["tool_call_id"] == "call_xyz"


class TestSaveLoadStructuredFields:
    """保存 → 重新加载，结构化字段不丢失"""

    @pytest.mark.asyncio
    async def test_tool_calls_persist_across_reload(self, session_manager):
        sm = session_manager
        sid = await sm.create_session("task")

        await sm.add_message(
            "assistant", "I'll check the file",
            tool_calls=[{"name": "run_shell", "arguments": '{"command":"cat file"}'}],
            reasoning_content="need to read file",
        )
        await sm.add_message("tool", "file content here", tool_call_id="call_1")
        await sm._save_session()

        sm2 = SessionManager(sm.project_path)
        ok = await sm2.switch_session(sid)
        assert ok

        msgs = await sm2.get_messages(include_system=False)
        relevant = [m for m in msgs if m["role"] in ("assistant", "tool")]
        assert len(relevant) >= 2
        assistant_msg = relevant[-2]
        tool_msg = relevant[-1]
        assert assistant_msg["tool_calls"][0]["name"] == "run_shell"
        assert assistant_msg["reasoning_content"] == "need to read file"
        assert tool_msg["tool_call_id"] == "call_1"


class TestStructuredMessagesGet:
    """get_messages 统一返回结构化字段"""

    @pytest.mark.asyncio
    async def test_get_messages_returns_structured_fields(self, session_manager):
        sm = session_manager
        sid = await sm.create_session("task")

        # 直接构造带结构化字段的消息
        sm.current_messages.append(SessionMessage(
            role="assistant", content="thinking",
            timestamp="2026-01-01T00:00:00",
            tool_calls=[{"name": "run_shell", "arguments": "{}"}],
        ))
        sm.current_messages.append(SessionMessage(
            role="tool", content="result",
            timestamp="2026-01-01T00:00:01",
            tool_call_id="c1",
        ))
        await sm._save_session()

        sm2 = SessionManager(sm.project_path)
        await sm2.switch_session(sid)
        msgs = await sm2.get_messages(include_system=False)

        assistants = [m for m in msgs if m["role"] == "assistant"]
        tools = [m for m in msgs if m["role"] == "tool"]
        assert len(assistants) >= 1
        assert len(tools) >= 1
        assert assistants[0]["tool_calls"][0]["name"] == "run_shell"
        assert tools[0]["tool_call_id"] == "c1"

    @pytest.mark.asyncio
    async def test_get_messages_plain_text(self, session_manager):
        sm = session_manager
        sid = await sm.create_session("task")
        await sm.add_message("assistant", "plain text without tool_calls")

        msgs = await sm.get_messages(include_system=False)
        last = msgs[-1]
        assert last["role"] == "assistant"
        assert last["content"] == "plain text without tool_calls"
        assert "tool_calls" not in last


class TestRealWorldScenario:
    """模拟真实多轮对话保存/恢复"""

    @pytest.mark.asyncio
    async def test_multi_turn_conversation(self, session_manager):
        sm = session_manager
        sid = await sm.create_session("do something")

        await sm.add_message(
            "assistant", "let me check",
            tool_calls=[{"id": "c1", "name": "run_shell", "arguments": '{"command":"ls"}'}],
            reasoning_content="need to list files",
        )
        await sm.add_message("tool", "file1.py file2.py", tool_call_id="c1")
        await sm.add_message("assistant", "done")

        sm2 = SessionManager(sm.project_path)
        await sm2.switch_session(sid)
        msgs = await sm2.get_messages(include_system=False)

        assistants = [m for m in msgs if m["role"] == "assistant"]
        tools = [m for m in msgs if m["role"] == "tool"]
        assert len(assistants) >= 2
        assert len(tools) == 1
        assert "tool_calls" in assistants[0]
        assert assistants[0]["reasoning_content"] == "need to list files"
        assert assistants[1]["content"] == "done"
        assert tools[0]["tool_call_id"] == "c1"
