# -*- coding: utf-8 -*-
"""
方案 B 测试：todo_write 状态管理与 main.py 注入逻辑。

覆盖：
1. todo_write.execute 后模块级状态正确更新（replace / merge 两种模式）
2. get_active_todos() 返回浅拷贝，外部修改不影响内部状态
3. clear_todos() 清空状态
4. _inject_todos_into_messages：无 todo 时不注入（零浪费）
5. _inject_todos_into_messages：有未完成项时注入到 system 末尾
6. _inject_todos_into_messages：全部完成时清空状态且不注入
7. _inject_todos_into_messages：不污染原 messages 列表
8. _inject_todos_into_messages：messages 无 system 时首位补 system
"""
import pytest

from abyss.tools.todo_write import (
    TodoWriteTool,
    get_active_todos,
    clear_todos,
)


@pytest.fixture(autouse=True)
def _reset_todo_state():
    """每用例前清空模块级 todo 状态，避免用例间相互污染。"""
    clear_todos()
    yield
    clear_todos()


def _todo(tid, content, status="pending", priority="medium"):
    return {"id": tid, "content": content, "status": status, "priority": priority}


# ---------- 状态管理 ----------

def test_execute_replace_updates_state():
    """replace 模式：execute 后模块级状态应为传入的 todos。"""
    tool = TodoWriteTool()
    todos = [_todo("1", "任务A", "pending"), _todo("2", "任务B", "in_progress")]

    tool.execute(todos=todos, merge=False)

    active = get_active_todos()
    assert len(active) == 2
    assert {t["id"] for t in active} == {"1", "2"}


def test_execute_merge_updates_by_id():
    """merge 模式：按 id 合并更新，未在传入列表中的项保留。"""
    tool = TodoWriteTool()
    # 初始化：两条 pending
    tool.execute(todos=[_todo("1", "任务A", "pending"), _todo("2", "任务B", "pending")], merge=False)
    # merge 更新：把 id=1 改为 completed
    tool.execute(todos=[_todo("1", "任务A", "completed")], merge=True)

    active = get_active_todos()
    assert len(active) == 2  # id=2 仍保留
    by_id = {t["id"]: t for t in active}
    assert by_id["1"]["status"] == "completed"
    assert by_id["2"]["status"] == "pending"


def test_get_active_todos_returns_copy():
    """get_active_todos() 返回浅拷贝，外部修改不应影响内部状态。"""
    tool = TodoWriteTool()
    tool.execute(todos=[_todo("1", "任务A", "pending")], merge=False)

    snapshot = get_active_todos()
    snapshot[0]["status"] = "completed"  # 外部修改

    # 内部状态不应被影响
    assert get_active_todos()[0]["status"] == "pending"


def test_clear_todos_empties_state():
    """clear_todos() 后 get_active_todos() 应返回空列表。"""
    tool = TodoWriteTool()
    tool.execute(todos=[_todo("1", "任务A", "pending")], merge=False)
    assert len(get_active_todos()) == 1

    clear_todos()

    assert get_active_todos() == []


# ---------- 注入逻辑 ----------

def test_inject_no_todos_returns_unchanged():
    """无 todo 状态时，_inject_todos_into_messages 应原样返回（不注入）。"""
    from abyss.main import _inject_todos_into_messages

    messages = [{"role": "system", "content": "原始 system"}, {"role": "user", "content": "hi"}]

    result = _inject_todos_into_messages(messages)

    assert result == messages
    assert result[0]["content"] == "原始 system"


def test_inject_with_incomplete_todos_appends_to_system():
    """有未完成 todo 时，应追加到 system 消息末尾。"""
    from abyss.main import _inject_todos_into_messages
    tool = TodoWriteTool()
    tool.execute(todos=[
        _todo("1", "任务A", "pending"),
        _todo("2", "任务B", "in_progress"),
    ], merge=False)

    messages = [{"role": "system", "content": "原始 system"}, {"role": "user", "content": "hi"}]
    result = _inject_todos_into_messages(messages)

    assert "原始 system" in result[0]["content"]
    assert "任务A" in result[0]["content"]
    assert "任务B" in result[0]["content"]
    assert "当前任务进度" in result[0]["content"]


def test_inject_all_completed_clears_state_and_skips():
    """全部完成时：清空状态且不注入（避免无意义信息）。"""
    from abyss.main import _inject_todos_into_messages
    tool = TodoWriteTool()
    tool.execute(todos=[_todo("1", "任务A", "completed")], merge=False)

    messages = [{"role": "system", "content": "原始 system"}]
    result = _inject_todos_into_messages(messages)

    # 不注入
    assert result == messages
    # 状态被清空
    assert get_active_todos() == []


def test_inject_does_not_mutate_original_messages():
    """注入应在副本上操作，不污染原 messages 列表。"""
    from abyss.main import _inject_todos_into_messages
    tool = TodoWriteTool()
    tool.execute(todos=[_todo("1", "任务A", "pending")], merge=False)

    original = [{"role": "system", "content": "原始 system"}, {"role": "user", "content": "hi"}]
    _inject_todos_into_messages(original)

    # 原 messages 不应被修改
    assert original[0]["content"] == "原始 system"
    assert len(original) == 2


def test_inject_no_system_message_prepends_one():
    """messages 无 system 时，应在首位补一条 system。"""
    from abyss.main import _inject_todos_into_messages
    tool = TodoWriteTool()
    tool.execute(todos=[_todo("1", "任务A", "pending")], merge=False)

    messages = [{"role": "user", "content": "hi"}]
    result = _inject_todos_into_messages(messages)

    assert result[0]["role"] == "system"
    assert "任务A" in result[0]["content"]
    assert result[1] == messages[0]


def test_inject_orders_in_progress_first():
    """注入时应按状态排序：in_progress > pending > completed。"""
    from abyss.main import _inject_todos_into_messages
    tool = TodoWriteTool()
    tool.execute(todos=[
        _todo("3", "已完成", "completed"),
        _todo("1", "进行中", "in_progress"),
        _todo("2", "待办", "pending"),
    ], merge=False)

    messages = [{"role": "system", "content": "sys"}]
    result = _inject_todos_into_messages(messages)
    injected_text = result[0]["content"]

    # in_progress 应出现在 pending 和 completed 之前
    idx_in_progress = injected_text.index("进行中")
    idx_pending = injected_text.index("待办")
    idx_completed = injected_text.index("已完成")
    assert idx_in_progress < idx_pending < idx_completed
