"""
测试会话数据完整性 —— 修复后的全面验证

覆盖场景：
1. _save_session() 保留 structured_messages 字段
2. _save_structured_messages() 同步更新内存缓存
3. 多轮任务间 tool 消息在 structured_messages 中累积不丢失
4. get_messages() 在 session 重载后返回完整数据
5. react_loop 历史过滤保留 tool 消息（单元层面验证）
6. 会话重载后 structured_messages 与 current_messages 一致
"""
import sys
import tempfile
import asyncio
import json
from pathlib import Path

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

import pytest
from aacode.utils.session_manager import SessionManager


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


def _read_session_file(sm):
    """直接读取会话 JSON 文件，绕过 SessionManager 缓存"""
    f = sm.sessions_dir / f"{sm.current_session_id}.json"
    with open(f, "r") as fh:
        return json.load(fh)


class TestSaveSessionPreservesStructuredMessages:
    """_save_session 不破坏 structured_messages"""

    @pytest.mark.asyncio
    async def test_save_session_keeps_existing_structured(self, sm):
        sid = await sm.create_session("test")
        raw = _read_session_file(sm)
        assert "structured_messages" not in raw

        structured = [
            {"role": "user", "content": "hello"},
            {"role": "assistant", "content": "world", "tool_calls": []},
            {"role": "tool", "content": "result", "tool_call_id": "c1"},
        ]
        await sm._save_structured_messages(structured)
        raw = _read_session_file(sm)
        assert "structured_messages" in raw
        assert len(raw["structured_messages"]) == 3

        await sm.add_message("user", "another message")
        raw = _read_session_file(sm)
        assert "structured_messages" in raw
        assert len(raw["structured_messages"]) == 4
        assert raw["structured_messages"][-1]["content"] == "another message"

    @pytest.mark.asyncio
    async def test_multiple_saves_preserve_structured(self, sm):
        sid = await sm.create_session("test")
        structured = [
            {"role": "user", "content": "msg1"},
            {"role": "assistant", "content": "resp1"},
        ]
        await sm._save_structured_messages(structured)

        for i in range(5):
            await sm.add_message("user", f"msg{i}")
            await sm.add_message("assistant", f"resp{i}")

        raw = _read_session_file(sm)
        assert "structured_messages" in raw
        assert len(raw["structured_messages"]) == 12
        assert raw["structured_messages"][-1]["content"] == "resp4"


class TestSaveStructuredUpdatesCache:
    """_save_structured_messages 同步更新内存 _structured_messages"""

    @pytest.mark.asyncio
    async def test_cache_updated_after_save(self, sm):
        await sm.create_session("test")
        assert sm._structured_messages is None

        structured = [{"role": "user", "content": "hi"}]
        await sm._save_structured_messages(structured)
        assert sm._structured_messages is not None
        assert len(sm._structured_messages) == 1
        assert sm._structured_messages[0]["content"] == "hi"

    @pytest.mark.asyncio
    async def test_cache_overwritten_on_second_save(self, sm):
        await sm.create_session("test")
        await sm._save_structured_messages([{"role": "user", "content": "first"}])
        assert sm._structured_messages[0]["content"] == "first"

        await sm._save_structured_messages([{"role": "user", "content": "second"}])
        assert sm._structured_messages[0]["content"] == "second"

    @pytest.mark.asyncio
    async def test_get_messages_after_cache_update(self, sm):
        await sm.create_session("test")
        await sm._save_structured_messages([
            {"role": "user", "content": "q1"},
            {"role": "assistant", "content": "a1"},
        ])
        msgs = await sm.get_messages(include_system=False)
        assert len(msgs) >= 2
        assert msgs[0]["role"] == "user"


class TestToolMessagesAccumulateAcrossTasks:
    """模拟多轮任务，tool 消息累积不丢失"""

    @pytest.mark.asyncio
    async def test_tool_messages_from_prior_task_survive(self, sm):
        await sm.create_session("test")

        task1_msgs = [
            {"role": "user", "content": "Task: do A"},
            {"role": "assistant", "content": "ok", "tool_calls": [{"name": "run_shell"}]},
            {"role": "tool", "content": "result_A", "tool_call_id": "c1"},
        ]
        await sm._save_structured_messages(task1_msgs)

        msgs_before = await sm.get_messages(include_system=False)
        tool_count_before = len([m for m in msgs_before if m["role"] == "tool"])
        assert tool_count_before == 1

        task2_msgs_base = [
            {"role": "user", "content": "Task: do B"},
            {"role": "assistant", "content": "ok", "tool_calls": [{"name": "search"}]},
            {"role": "tool", "content": "result_B", "tool_call_id": "c2"},
        ]
        await sm._save_structured_messages(task2_msgs_base)

        msgs_after = await sm.get_messages(include_system=False)
        tool_count_after = len([m for m in msgs_after if m["role"] == "tool"])
        assert tool_count_after == 1


class TestReloadSessionConsistency:
    """会话重载后数据一致性"""

    @pytest.mark.asyncio
    async def test_reload_gets_structured_messages(self, sm):
        sid = await sm.create_session("test")
        structured = [
            {"role": "user", "content": "q"},
            {"role": "assistant", "content": "a", "tool_calls": []},
            {"role": "tool", "content": "r", "tool_call_id": "c1"},
        ]
        await sm._save_structured_messages(structured)

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

        msgs = await sm2.get_messages(include_system=False)
        roles = [m["role"] for m in msgs]
        assert "user" in roles
        assert "assistant" in roles
        assert "tool" in roles

        tool_msgs = [m for m in msgs if m["role"] == "tool"]
        assert len(tool_msgs) == 1
        assert tool_msgs[0]["tool_call_id"] == "c1"

    @pytest.mark.asyncio
    async def test_add_message_after_reload(self, sm):
        sid = await sm.create_session("test")
        await sm._save_structured_messages([
            {"role": "user", "content": "original"},
            {"role": "assistant", "content": "response"},
        ])

        sm2 = SessionManager(sm.project_path)
        await sm2.switch_session(sid)
        assert sm2._structured_messages is not None

        await sm2.add_message("user", "new question")
        msgs = await sm2.get_messages(include_system=False)
        contents = [m["content"] for m in msgs if m["role"] == "user"]
        assert any("original" in c for c in contents)
        assert any("new question" in c for c in contents)


class TestGetSessionConsistency:
    """get_session API 返回完整数据"""

    @pytest.mark.asyncio
    async def test_get_session_returns_structured_messages(self, sm):
        sid = await sm.create_session("test")
        structured = [
            {"role": "user", "content": "hello"},
            {"role": "assistant", "content": "hi", "tool_calls": [{"name": "run_shell"}]},
            {"role": "tool", "content": "output", "tool_call_id": "c1"},
        ]
        await sm._save_structured_messages(structured)

        session_data = await sm.get_session(sid)
        assert "messages" in session_data
        msgs = session_data["messages"]
        roles = [m["role"] for m in msgs]
        assert "user" in roles
        assert "assistant" in roles
        assert "tool" in roles

    @pytest.mark.asyncio
    async def test_get_session_after_reload(self, sm):
        sid = await sm.create_session("test")
        await sm.add_message("user", "first msg")
        await sm.add_message("assistant", "first resp")
        await sm._save_structured_messages([
            {"role": "user", "content": "first msg"},
            {"role": "assistant", "content": "first resp"},
        ])

        sm2 = SessionManager(sm.project_path)
        await sm2.switch_session(sid)
        session_data = await sm2.get_session(sid)
        msgs = session_data["messages"]
        assert len(msgs) >= 2
        assert any("first msg" in m.get("content", "") for m in msgs)
