"""Tests for file system tools including bash, edit, find, grep, ls, read, and write tools."""

import asyncio
import os
import tempfile
from pathlib import Path


async def test_bash_tool():
    """Test BashTool."""
    from reme.tool.fs import BashTool

    print("=== Testing BashTool ===")
    bash_tool = BashTool()
    result = await bash_tool.call(command="echo 'Hello World'")
    print(f"Result: {result}")
    assert "Hello World" in result
    print("✓ BashTool test passed\n")


async def test_edit_tool():
    """Test EditTool."""
    from reme.tool.fs import EditTool

    print("=== Testing EditTool ===")

    # Create temp file
    with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
        temp_path = f.name
        f.write("Hello World\nThis is a test\nGoodbye World\n")

    try:
        # Test edit
        edit_tool = EditTool()
        result = await edit_tool.call(
            path=temp_path,
            oldText="This is a test",
            newText="This is an updated test",
        )
        print(f"Result: {result}")

        # Verify content
        with open(temp_path, "r", encoding="utf-8") as f:
            content = f.read()

        assert "This is an updated test" in content
        assert "This is a test" not in content
        print("✓ EditTool test passed\n")

        # Test error: file not found
        print("=== Testing file not found error ===")
        result = await edit_tool.call(
            path="/nonexistent/file.txt",
            oldText="test",
            newText="new",
        )
        print(f"Expected error result: {result}")
        assert "failed" in result and "File not found" in result
        print("✓ File not found error test passed\n")

        # Test error: text not found
        print("=== Testing text not found error ===")
        result = await edit_tool.call(
            path=temp_path,
            oldText="nonexistent text",
            newText="new",
        )
        print(f"Expected error result: {result}")
        assert "failed" in result and "Could not find" in result
        print("✓ Text not found error test passed\n")

    finally:
        # Cleanup
        if os.path.exists(temp_path):
            os.unlink(temp_path)


async def test_find_tool():
    """Test FindTool."""
    from reme.tool.fs import FindTool

    print("=== Testing FindTool ===")

    # Create temp directory with test files
    with tempfile.TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir)

        # Create some test files
        (temp_path / "test1.txt").write_text("test file 1")
        (temp_path / "test2.txt").write_text("test file 2")
        (temp_path / "readme.md").write_text("readme")

        # Create subdirectory with files
        sub_dir = temp_path / "subdir"
        sub_dir.mkdir()
        (sub_dir / "test3.txt").write_text("test file 3")
        (sub_dir / "config.json").write_text("{}")

        # Create .gitignore to ignore certain files
        (temp_path / ".gitignore").write_text("*.md\n")

        # Test: find all txt files
        find_tool = FindTool(cwd=str(temp_path))
        result = await find_tool.call(pattern="*.txt")
        print(f"Find *.txt result:\n{result}")
        assert "test1.txt" in result
        assert "test2.txt" in result
        assert "readme.md" not in result  # Should be ignored by .gitignore
        print("✓ Find *.txt test passed\n")

        # Test: find with recursive pattern
        result = await find_tool.call(pattern="**/*.txt")
        print(f"Find **/*.txt result:\n{result}")
        assert "test1.txt" in result
        assert "subdir/test3.txt" in result or "test3.txt" in result
        print("✓ Find **/*.txt test passed\n")

        # Test: find with no matches
        result = await find_tool.call(pattern="*.nonexistent")
        print(f"Find *.nonexistent result:\n{result}")
        assert "No files found" in result
        print("✓ No matches test passed\n")

        # Test: error - directory not found
        print("=== Testing directory not found error ===")
        result = await find_tool.call(pattern="*.txt", path="/nonexistent/dir")
        print(f"Expected error result: {result}")
        assert "failed" in result and "Path not found" in result
        print("✓ Directory not found error test passed\n")


async def test_grep_tool():
    """Test GrepTool."""
    from reme.tool.fs import GrepTool

    print("=== Testing GrepTool ===")

    # Create temp directory with test files
    with tempfile.TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir)

        # Create test files with searchable content
        (temp_path / "file1.txt").write_text("Hello World\nThis is a test\nGoodbye World\n")
        (temp_path / "file2.txt").write_text("Another test file\nWith multiple lines\nHello again\n")
        (temp_path / "script.py").write_text("def hello():\n    print('Hello')\n    return True\n")

        # Create subdirectory with files
        sub_dir = temp_path / "subdir"
        sub_dir.mkdir()
        (sub_dir / "nested.txt").write_text("Nested file content\nWith hello keyword\n")

        # Test: search for pattern
        grep_tool = GrepTool(cwd=str(temp_path))
        result = await grep_tool.call(pattern="Hello", path=str(temp_path))
        print(f"Search 'Hello' result:\n{result}")
        assert "file1.txt" in result
        assert "Hello World" in result or "Hello" in result
        print("✓ Basic search test passed\n")

        # Test: case-insensitive search
        result = await grep_tool.call(pattern="hello", path=str(temp_path), ignoreCase=True)
        print(f"Case-insensitive search result:\n{result}")
        assert "file1.txt" in result or "Hello" in result.lower()
        print("✓ Case-insensitive search test passed\n")

        # Test: literal string search
        result = await grep_tool.call(pattern="Hello()", path=str(temp_path), literal=True)
        print(f"Literal search result:\n{result}")
        # Should not find regex interpretation
        print("✓ Literal search test passed\n")

        # Test: glob filter
        result = await grep_tool.call(pattern="Hello", path=str(temp_path), glob="*.txt")
        print(f"Glob filter *.txt result:\n{result}")
        assert "file1.txt" in result or "file2.txt" in result
        assert ".py" not in result  # Python files should be excluded
        print("✓ Glob filter test passed\n")

        # Test: context lines
        result = await grep_tool.call(pattern="test", path=str(temp_path), contextLines=1)
        print(f"Context lines result:\n{result}")
        # Should include lines before and after matches
        print("✓ Context lines test passed\n")

        # Test: limit matches
        result = await grep_tool.call(pattern="Hello", path=str(temp_path), limit=1)
        print(f"Limit to 1 match result:\n{result}")
        assert "limit reached" in result or result.count(":") >= 1
        print("✓ Limit test passed\n")

        # Test: no matches
        result = await grep_tool.call(pattern="nonexistent_pattern_xyz", path=str(temp_path))
        print(f"No matches result:\n{result}")
        assert "No matches found" in result
        print("✓ No matches test passed\n")

        # Test: error - path not found
        print("=== Testing path not found error ===")
        try:
            result = await grep_tool.call(pattern="test", path="/nonexistent/path")
            assert "failed" in result and "not found" in result
        except Exception as e:
            assert "not found" in str(e).lower()
        print("✓ Path not found error test passed\n")


async def test_ls_tool():
    """Test LsTool."""
    from reme.tool.fs import LsTool

    print("=== Testing LsTool ===")

    # Create temp directory with test files
    with tempfile.TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir)

        # Create test files and directories
        (temp_path / "file1.txt").write_text("test file 1")
        (temp_path / "file2.py").write_text("test file 2")
        (temp_path / ".hidden").write_text("hidden file")
        (temp_path / "README.md").write_text("readme")

        # Create subdirectories
        (temp_path / "subdir1").mkdir()
        (temp_path / "subdir2").mkdir()

        # Test: list current directory
        ls_tool = LsTool(cwd=str(temp_path))
        result = await ls_tool.call()
        print(f"List directory result:\n{result}")
        assert ".hidden" in result  # Includes dotfiles
        assert "file1.txt" in result
        assert "file2.py" in result
        assert "subdir1/" in result  # Directories have '/' suffix
        assert "subdir2/" in result
        print("✓ Basic ls test passed\n")

        # Test: list specific path
        result = await ls_tool.call(path=".")
        print(f"List current directory result:\n{result}")
        assert "file1.txt" in result
        print("✓ Specific path test passed\n")

        # Test: empty directory
        empty_dir = temp_path / "empty"
        empty_dir.mkdir()
        result = await ls_tool.call(path="empty")
        print(f"Empty directory result:\n{result}")
        assert "(empty directory)" in result
        print("✓ Empty directory test passed\n")

        # Test: entry limit
        # Create many files
        for i in range(10):
            (temp_path / f"file{i:03d}.txt").write_text(f"file {i}")

        result = await ls_tool.call(limit=5)
        print(f"Limited entries result:\n{result}")
        assert "entries limit reached" in result
        assert "limit=10" in result  # Should suggest doubling the limit
        print("✓ Entry limit test passed\n")

        # Test: error - path not found
        print("=== Testing path not found error ===")
        result = await ls_tool.call(path="/nonexistent/path")
        print(f"Expected error result: {result}")
        assert "failed" in result and "Path not found" in result
        print("✓ Path not found error test passed\n")

        # Test: error - not a directory
        print("=== Testing not a directory error ===")
        result = await ls_tool.call(path="file1.txt")
        print(f"Expected error result: {result}")
        assert "failed" in result and "Not a directory" in result
        print("✓ Not a directory error test passed\n")


async def test_read_tool():
    """Test ReadTool."""
    from reme.tool.fs import ReadTool

    print("=== Testing ReadTool ===")

    # Create temp directory with test files
    with tempfile.TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir)

        # Create test text file
        test_file = temp_path / "test.txt"
        test_content = "\n".join([f"Line {i}" for i in range(1, 101)])  # 100 lines
        test_file.write_text(test_content)

        # Create test image file
        image_file = temp_path / "test.jpg"
        image_file.write_bytes(b"\xff\xd8\xff\xe0")  # Minimal JPEG header

        # Test: read full file
        read_tool = ReadTool(cwd=str(temp_path))
        result = await read_tool.call(path="test.txt")
        print(f"Read full file result:\n{result[:200]}...")
        assert "Line 1" in result
        assert "Line 100" in result
        print("✓ Read full file test passed\n")

        # Test: read with offset
        result = await read_tool.call(path="test.txt", offset=50)
        print(f"Read with offset=50 result:\n{result[:200]}...")
        # Check that we start from Line 50 (should be first line of content)
        assert result.startswith("Line 50"), f"Should start with 'Line 50', got: {result[:50]}"
        assert "Line 100" in result
        print("✓ Read with offset test passed\n")

        # Test: read with limit
        result = await read_tool.call(path="test.txt", limit=10)
        print(f"Read with limit=10 result:\n{result}")
        assert "Line 1" in result
        assert "Line 10" in result or "more lines in file" in result
        assert "Line 50" not in result
        print("✓ Read with limit test passed\n")

        # Test: read with offset and limit
        result = await read_tool.call(path="test.txt", offset=20, limit=5)
        print(f"Read with offset=20, limit=5 result:\n{result}")
        assert "Line 20" in result
        assert "Line 24" in result or "more lines" in result
        print("✓ Read with offset and limit test passed\n")

        # Test: read image file
        result = await read_tool.call(path="test.jpg")
        print(f"Read image result:\n{result}")
        assert "image file" in result.lower() or ".jpg" in result.lower()
        print("✓ Read image test passed\n")

        # Test: offset beyond file
        print("=== Testing offset beyond file error ===")
        result = await read_tool.call(path="test.txt", offset=200)
        print(f"Expected error result: {result}")
        assert "failed" in result and ("beyond end of file" in result or "offset" in result.lower())
        print("✓ Offset beyond file error test passed\n")

        # Test: file not found
        print("=== Testing file not found error ===")
        result = await read_tool.call(path="nonexistent.txt")
        print(f"Expected error result: {result}")
        assert "failed" in result and "not found" in result.lower()
        print("✓ File not found error test passed\n")

        # Test: read directory (should fail)
        print("=== Testing read directory error ===")
        sub_dir = temp_path / "subdir"
        sub_dir.mkdir()
        result = await read_tool.call(path="subdir")
        print(f"Expected error result: {result}")
        assert "failed" in result and ("Not a file" in result or "directory" in result.lower())
        print("✓ Read directory error test passed\n")


async def test_write_tool():
    """Test WriteTool."""
    from reme.tool.fs import WriteTool

    print("=== Testing WriteTool ===")

    # Create temp directory
    with tempfile.TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir)

        # Test: write new file
        write_tool = WriteTool(cwd=str(temp_path))
        test_content = "Hello World\nThis is a test file\n"
        result = await write_tool.call(path="test.txt", content=test_content)
        print(f"Write result: {result}")
        assert "Successfully wrote" in result
        assert "test.txt" in result

        # Verify file was created
        test_file = temp_path / "test.txt"
        assert test_file.exists()
        assert test_file.read_text() == test_content
        print("✓ Write new file test passed\n")

        # Test: overwrite existing file
        new_content = "Updated content\n"
        result = await write_tool.call(path="test.txt", content=new_content)
        print(f"Overwrite result: {result}")
        assert "Successfully wrote" in result

        # Verify file was overwritten
        assert test_file.read_text() == new_content
        assert test_content not in test_file.read_text()
        print("✓ Overwrite existing file test passed\n")

        # Test: create file with parent directories
        nested_path = "subdir1/subdir2/nested.txt"
        nested_content = "Nested file content"
        result = await write_tool.call(path=nested_path, content=nested_content)
        print(f"Create with parents result: {result}")
        assert "Successfully wrote" in result

        # Verify nested file was created
        nested_file = temp_path / "subdir1" / "subdir2" / "nested.txt"
        assert nested_file.exists()
        assert nested_file.read_text() == nested_content
        print("✓ Create file with parent directories test passed\n")

        # Test: write empty file
        result = await write_tool.call(path="empty.txt", content="")
        print(f"Write empty file result: {result}")
        assert "Successfully wrote" in result
        assert "0 bytes" in result

        # Verify empty file
        empty_file = temp_path / "empty.txt"
        assert empty_file.exists()
        assert empty_file.read_text() == ""
        print("✓ Write empty file test passed\n")

        # Test: write file with absolute path
        abs_path = str(temp_path / "absolute.txt")
        abs_content = "Absolute path content"
        result = await write_tool.call(path=abs_path, content=abs_content)
        print(f"Write absolute path result: {result}")
        assert "Successfully wrote" in result

        # Verify absolute path file
        abs_file = Path(abs_path)
        assert abs_file.exists()
        assert abs_file.read_text(encoding="utf-8") == abs_content
        print("✓ Write absolute path test passed\n")


async def main():
    """Run all file system tool tests."""
    await test_bash_tool()
    await test_edit_tool()
    await test_find_tool()
    await test_grep_tool()
    await test_ls_tool()
    await test_read_tool()
    await test_write_tool()
    print("=== All tests passed! ===")


if __name__ == "__main__":
    asyncio.run(main())
