import os
from pathlib import Path

from tools.truncation import truncate_and_spill


def test_truncate_and_spill_small_returns_original(tmp_path, monkeypatch):
    """小内容不截断，直接返回原文"""
    monkeypatch.chdir(tmp_path)
    content = "hello\nworld"
    r = truncate_and_spill(content, tool_name="x", max_bytes=1024, max_lines=2000)

    print(f"\n--- 小内容不截断 ---")
    print(f"  truncated={r.truncated}, preview_bytes={r.preview_bytes}")

    assert r.truncated is False
    assert r.output_path is None
    assert r.preview == content


def test_truncate_and_spill_spills_to_local_dundun(tmp_path, monkeypatch):
    """超限内容截断并溢出到 .dundun/tool-output/"""
    monkeypatch.chdir(tmp_path)

    content = "a" * 5000
    r = truncate_and_spill(content, tool_name="big", max_bytes=100, max_lines=10)

    print(f"\n--- 超限截断溢出 ---")
    print(f"  truncated={r.truncated}, output_path={r.output_path}")
    print(f"  original_bytes={r.original_bytes}, preview_bytes={r.preview_bytes}")

    assert r.truncated is True
    assert r.output_path is not None
    p = Path(r.output_path)
    assert p.exists()

    norm = str(p).replace("\\", "/")
    assert "/.dundun/tool-output/" in norm

    saved = p.read_text(encoding="utf-8", errors="ignore")
    assert saved == content
    assert "Full output saved to:" in r.preview


def test_truncate_by_line_count(tmp_path, monkeypatch):
    """超过行数限制时截断"""
    monkeypatch.chdir(tmp_path)

    # 生成 100 行内容，限制 10 行
    lines = [f"line_{i}" for i in range(100)]
    content = "\n".join(lines)
    r = truncate_and_spill(content, tool_name="lines", max_bytes=1024 * 1024, max_lines=10)

    print(f"\n--- 行数截断 ---")
    print(f"  truncated={r.truncated}")
    print(f"  preview 行数={r.preview.count(chr(10))}")

    assert r.truncated is True
    # preview 应该只包含前 10 行的内容
    preview_lines = r.preview.split("\n")
    # 前 10 行 + 截断提示
    assert "line_0" in r.preview
    assert "line_9" in r.preview
    assert "truncated" in r.preview.lower()


def test_truncate_by_byte_limit(tmp_path, monkeypatch):
    """超过字节限制时截断"""
    monkeypatch.chdir(tmp_path)

    # 生成 5 行，每行 100 字符，限制 200 字节
    lines = ["x" * 100 for _ in range(5)]
    content = "\n".join(lines)
    r = truncate_and_spill(content, tool_name="bytes", max_bytes=200, max_lines=10000)

    print(f"\n--- 字节截断 ---")
    print(f"  truncated={r.truncated}")
    print(f"  original_bytes={r.original_bytes}, preview_bytes={r.preview_bytes}")

    assert r.truncated is True
    assert r.preview_bytes <= 200
    assert r.original_bytes > 200


def test_truncate_none_content(tmp_path, monkeypatch):
    """None 内容应安全处理"""
    monkeypatch.chdir(tmp_path)

    r = truncate_and_spill(None, tool_name="null")

    print(f"\n--- None 内容 ---")
    print(f"  truncated={r.truncated}, preview={r.preview!r}")

    assert r.truncated is False
    assert r.preview == ""


def test_truncate_empty_content(tmp_path, monkeypatch):
    """空字符串不截断"""
    monkeypatch.chdir(tmp_path)

    r = truncate_and_spill("", tool_name="empty")

    print(f"\n--- 空内容 ---")
    print(f"  truncated={r.truncated}")

    assert r.truncated is False
    assert r.preview == ""


def test_truncate_unicode_content(tmp_path, monkeypatch):
    """Unicode 内容的字节截断不应产生乱码"""
    monkeypatch.chdir(tmp_path)

    # 中文字符每个约 3 字节 (UTF-8)
    content = "中文测试" * 100  # 400 字符，约 1200 字节
    r = truncate_and_spill(content, tool_name="unicode", max_bytes=100, max_lines=10000)

    print(f"\n--- Unicode 截断 ---")
    print(f"  truncated={r.truncated}")
    print(f"  preview[:30]={r.preview[:30]!r}")

    assert r.truncated is True
    # 确保截断后的文本是有效的 UTF-8（不会截断字符中间）
    try:
        r.preview.encode("utf-8")
    except UnicodeEncodeError:
        assert False, "截断后的预览不是有效的 UTF-8"


def test_truncate_exactly_at_limit(tmp_path, monkeypatch):
    """恰好在限制边界时不截断"""
    monkeypatch.chdir(tmp_path)

    # 恰好 10 行
    lines = [f"line_{i}" for i in range(10)]
    content = "\n".join(lines)
    content_bytes = len(content.encode("utf-8"))

    r = truncate_and_spill(
        content, tool_name="exact",
        max_bytes=content_bytes,
        max_lines=10,
    )

    print(f"\n--- 恰好边界 ---")
    print(f"  truncated={r.truncated}, content_bytes={content_bytes}")

    assert r.truncated is False
    assert r.preview == content


def test_truncate_output_file_unique(tmp_path, monkeypatch):
    """多次截断应生成不同的输出文件"""
    monkeypatch.chdir(tmp_path)

    content = "a" * 5000
    r1 = truncate_and_spill(content, tool_name="dup", max_bytes=100, max_lines=10)
    r2 = truncate_and_spill(content, tool_name="dup", max_bytes=100, max_lines=10)

    print(f"\n--- 文件唯一性 ---")
    print(f"  path1={r1.output_path}")
    print(f"  path2={r2.output_path}")

    assert r1.output_path != r2.output_path
    assert Path(r1.output_path).exists()
    assert Path(r2.output_path).exists()
