"""File system tools."""

import shutil
from pathlib import Path
from agent.tools import tool
from agent.ignore import is_ignored


def _protected(path: str) -> str:
    return f"Error: {path} is protected by .llamaignore"


def _resolve_destination(src: Path, dst: Path) -> Path:
    if dst.exists() and dst.is_dir():
        return dst / src.name
    return dst


@tool
def read_file(path: str) -> str:
    """Read the contents of a file.

    Args:
        path: Absolute or relative path to the file to read.
    """
    if is_ignored(path):
        return _protected(path)
    p = Path(path)
    if not p.exists():
        return f"Error: file not found: {path}"
    if not p.is_file():
        return f"Error: not a file: {path}"
    try:
        return p.read_text(encoding="utf-8")
    except PermissionError:
        return f"Error: permission denied: {path}"


@tool
def write_file(path: str, content: str) -> str:
    """Write content to a file, creating it if it does not exist.

    Args:
        path: Absolute or relative path of the file to write.
        content: Text content to write into the file.
    """
    if is_ignored(path):
        return _protected(path)
    p = Path(path)
    p.parent.mkdir(parents=True, exist_ok=True)
    p.write_text(content, encoding="utf-8")
    return f"Written {len(content)} characters to {path}"


@tool
def list_dir(path: str) -> str:
    """List files and directories at a path.

    Args:
        path: Directory path to list. Defaults to current directory.
    """
    p = Path(path) if path else Path(".")
    if is_ignored(str(p)):
        return _protected(str(p))
    if not p.exists():
        return f"Error: path does not exist: {path}"
    try:
        entries = sorted(p.iterdir(), key=lambda e: (e.is_file(), e.name))
    except PermissionError:
        return f"Error: permission denied: {path}"
    lines = []
    for entry in entries:
        prefix = "📄" if entry.is_file() else "📁"
        lines.append(f"{prefix} {entry.name}")
    return "\n".join(lines) if lines else "(empty directory)"


@tool
def make_dir(path: str) -> str:
    """Create a directory (and any missing parents).

    Args:
        path: Directory path to create.
    """
    if is_ignored(path):
        return _protected(path)
    Path(path).mkdir(parents=True, exist_ok=True)
    return f"Directory created: {path}"


@tool
def delete_file(path: str) -> str:
    """Delete a file.

    Args:
        path: Path of the file to delete.
    """
    if is_ignored(path):
        return _protected(path)
    p = Path(path)
    if not p.exists():
        return f"Error: file not found: {path}"
    if not p.is_file():
        return f"Error: not a file: {path}"
    p.unlink()
    return f"Deleted: {path}"


@tool
def move_file(src: str, dst: str) -> str:
    """Move or rename a file or directory.

    Args:
        src: Source path (file or directory).
        dst: Destination path. If dst is a directory, src is moved inside it.
    """
    if is_ignored(src):
        return _protected(src)
    s = Path(src)
    if not s.exists():
        return f"Error: source not found: {src}"
    d = Path(dst)
    final_dst = _resolve_destination(s, d)
    if is_ignored(str(final_dst)):
        return _protected(str(final_dst))
    final_dst.parent.mkdir(parents=True, exist_ok=True)
    shutil.move(str(s), str(d))
    return f"Moved: {src} → {dst}"


@tool
def copy_file(src: str, dst: str) -> str:
    """Copy a file to a new location.

    Args:
        src: Source file path.
        dst: Destination file path. Parent directories are created if needed.
    """
    if is_ignored(src):
        return _protected(src)
    s = Path(src)
    if not s.exists():
        return f"Error: source not found: {src}"
    if not s.is_file():
        return f"Error: not a file: {src}"
    d = Path(dst)
    final_dst = _resolve_destination(s, d)
    if is_ignored(str(final_dst)):
        return _protected(str(final_dst))
    final_dst.parent.mkdir(parents=True, exist_ok=True)
    shutil.copy2(str(s), str(d))
    return f"Copied: {src} → {dst}"
