"""
测试 react_loop.py — _detect_stale_loop() 死循环检测
"""
import sys
from pathlib import Path

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

from aacode.core.react_loop import AsyncReActLoop, ActionItem


class MockContextManager:
    async def get_context(self):
        return ""

    def save_large_output(self, *args, **kwargs):
        pass

    async def save_history(self, *args, **kwargs):
        pass


class MockTodoManager:
    pass


class TestDetectStaleLoop:
    """Fix 3a: _detect_stale_loop() 检测死循环模式"""

    def _make_loop(self):
        loop = AsyncReActLoop(
            model_caller=lambda x: None,
            tools={},
            context_manager=MockContextManager(),
            max_iterations=50,
            project_path=Path("/tmp"),
        )
        loop._stale_tracker = {
            "fetch_url_by_domain": {},
        }
        loop._stale_warnings_issued = set()
        return loop

    def test_other_tools_never_trigger(self):
        """非 fetch_url 工具永远不会触发 stale 检测"""
        loop = self._make_loop()
        actions = [ActionItem(action="run_shell", action_input={"command": "ls"})]
        warning = loop._detect_stale_loop(actions)
        assert warning is None

        actions = [ActionItem(action="run_shell", action_input={"path": "/tmp/x", "content": "x"})]
        warning = loop._detect_stale_loop(actions)
        assert warning is None

    def test_fetch_url_stale_domain_triggers(self):
        """连续 3 次同域名返回不可读内容触发警告"""
        loop = self._make_loop()
        loop._stale_tracker["fetch_url_by_domain"] = {
            "pytorch.org": [
                {"url": "https://pytorch.org/a", "has_content": False},
                {"url": "https://pytorch.org/b", "has_content": False},
                {"url": "https://pytorch.org/c", "has_content": False},
            ]
        }

        actions = [ActionItem(action="fetch_url", action_input={"url": "https://pytorch.org/d"})]
        warning = loop._detect_stale_loop(actions)
        assert warning is not None
        assert "pytorch.org" in warning
        assert "unreadable" in warning.lower()

    def test_fetch_url_domain_with_content_no_trigger(self):
        """有可读内容时不触发"""
        loop = self._make_loop()
        loop._stale_tracker["fetch_url_by_domain"] = {
            "pytorch.org": [
                {"url": "https://pytorch.org/a", "has_content": True},
                {"url": "https://pytorch.org/b", "has_content": False},
                {"url": "https://pytorch.org/c", "has_content": False},
            ]
        }

        actions = [ActionItem(action="fetch_url", action_input={"url": "https://pytorch.org/d"})]
        warning = loop._detect_stale_loop(actions)
        assert warning is None

    def test_warning_not_issued_twice(self):
        """同一域名警告不会重复注入"""
        loop = self._make_loop()
        loop._stale_tracker["fetch_url_by_domain"] = {
            "example.com": [
                {"url": "https://example.com/a", "has_content": False},
                {"url": "https://example.com/b", "has_content": False},
                {"url": "https://example.com/c", "has_content": False},
            ]
        }
        loop._stale_warnings_issued.add("fetch_url_stale_example.com")

        actions = [ActionItem(action="fetch_url", action_input={"url": "https://example.com/d"})]
        warning = loop._detect_stale_loop(actions)
        assert warning is None  # 已发过，不重复

    def test_record_fetch_url_result(self):
        """_record_fetch_url_result 正确记录结果"""
        loop = self._make_loop()

        loop._record_fetch_url_result("https://pytorch.org/a", "Empty page")
        loop._record_fetch_url_result("https://pytorch.org/b", "Empty page")
        loop._record_fetch_url_result(
            "https://pytorch.org/c",
            "<html><body><h1>" + "A" * 200 + "</h1></body></html>"
        )

        domain_tracker = loop._stale_tracker["fetch_url_by_domain"]
        assert "pytorch.org" in domain_tracker
        entries = domain_tracker["pytorch.org"]
        assert len(entries) == 3
        assert entries[0]["has_content"] is False
        assert entries[1]["has_content"] is False
        assert entries[2]["has_content"] is True


if __name__ == "__main__":
    t = TestDetectStaleLoop()
    all_pass = True
    for name in sorted(dir(t)):
        if name.startswith("test_"):
            try:
                getattr(t, name)()
                print(f"  {name}: PASS")
            except AssertionError as e:
                print(f"  {name}: FAIL - {e}")
                all_pass = False

    if all_pass:
        print("\nAll tests passed!")
    else:
        print("\nSome tests failed!")
