"""chat_messages / chat_summaries 与恢复逻辑。"""

from __future__ import annotations

import asyncio
import json
from pathlib import Path

import aiosqlite

from aicd.agent.chat_context import build_hydrated_messages
from aicd.db.store import TaskStore


def test_append_and_roundtrip_tool_rows(tmp_path: Path) -> None:
    async def _go() -> None:
        db = tmp_path / "t.db"
        store = TaskStore(db)
        conn = await store.connect()
        sid = "s1"
        await store.append_chat_message(conn, session_id=sid, role="user", content="hi")
        await store.append_chat_message(
            conn,
            session_id=sid,
            role="assistant",
            content="",
            tool_calls=[
                {
                    "id": "call_1",
                    "type": "function",
                    "function": {"name": "fs_read_file", "arguments": "{}"},
                }
            ],
        )
        await store.append_chat_message(
            conn,
            session_id=sid,
            role="tool",
            content=json.dumps({"ok": True, "path": "/x"}),
            tool_call_id="call_1",
            tool_name="fs_read_file",
        )
        rows = await store.list_chat_messages(conn, sid, limit=50, offset=0)
        assert len(rows) == 3
        assert rows[1].tool_calls_json
        tc = json.loads(rows[1].tool_calls_json or "[]")
        assert tc[0]["function"]["name"] == "fs_read_file"
        assert rows[2].role == "tool"
        assert rows[2].tool_call_id == "call_1"
        assert rows[2].tool_name == "fs_read_file"
        await conn.close()

    asyncio.run(_go())


def test_summary_and_hydrate_inject(tmp_path: Path) -> None:
    async def _go() -> None:
        db = tmp_path / "t2.db"
        store = TaskStore(db)
        conn = await store.connect()
        sid = "s2"
        for i in range(25):
            await store.append_chat_message(
                conn, session_id=sid, role="user", content=f"m{i}"
            )
        await store.append_chat_summary(
            conn, session_id=sid, content="SUMMARY", covers_up_to_message_id=10
        )
        total = await store.count_chat_messages(conn, sid)
        max_m = 10
        tail = min(total, max_m)
        offset = max(0, total - tail)
        rows = await store.list_chat_messages(conn, sid, limit=tail, offset=offset)
        truncated = total > max_m
        sums = await store.list_chat_summaries(conn, sid, limit=5)
        latest = sums[-1].content if sums else None
        msgs = build_hydrated_messages(
            rows=rows,
            truncated_by_count=truncated,
            latest_summary=latest,
            context_budget_tokens=50_000,
        )
        assert msgs[0]["role"] == "user"
        assert "摘记" in msgs[0]["content"]
        assert "SUMMARY" in msgs[0]["content"]
        await conn.close()

    asyncio.run(_go())


def test_migration_adds_columns(tmp_path: Path) -> None:
    """旧库仅有 5 列时迁移补 tool_call_id / tool_name。"""

    async def _go() -> None:
        db = tmp_path / "old.db"
        db.parent.mkdir(parents=True, exist_ok=True)
        conn = await aiosqlite.connect(db)
        old = """
        CREATE TABLE chat_messages (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            session_id TEXT NOT NULL,
            role TEXT NOT NULL,
            content TEXT,
            tool_calls_json TEXT,
            created_at TEXT NOT NULL
        );
        """
        await conn.executescript(old)
        await conn.commit()
        await conn.close()
        store = TaskStore(db)
        conn2 = await store.connect()
        cur = await conn2.execute("PRAGMA table_info(chat_messages)")
        cols = {r[1] for r in await cur.fetchall()}
        assert "tool_call_id" in cols
        assert "tool_name" in cols
        await conn2.close()

    asyncio.run(_go())
