"""
File Tools

File system operations for agents:
- File reading/writing
- Directory operations
- File search
- Content analysis
"""

from __future__ import annotations

import json
import logging
import os
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

logger = logging.getLogger(__name__)


class FileTools:
    """Tools for file system operations."""

    def __init__(self, base_path: str | None = None):
        """
        Initialize file tools.

        Args:
            base_path: Base path for file operations (for security)
        """
        self.base_path = Path(base_path) if base_path else Path.cwd()
        logger.info(f"FileTools initialized with base path: {self.base_path}")

    def _resolve_path(self, path: str) -> Path:
        """Resolve and validate a path."""
        resolved = (self.base_path / path).resolve()
        # Security check: ensure path is within base_path
        if not str(resolved).startswith(str(self.base_path.resolve())):
            raise ValueError(f"Path {path} is outside base directory")
        return resolved

    def read_file(
        self,
        path: str,
        encoding: str = "utf-8",
        max_size_mb: float = 10.0,
    ) -> dict[str, Any]:
        """
        Read contents of a file.

        Args:
            path: File path (relative to base_path)
            encoding: File encoding
            max_size_mb: Maximum file size to read in MB
        """
        try:
            file_path = self._resolve_path(path)

            if not file_path.exists():
                return {"success": False, "error": f"File not found: {path}"}

            if not file_path.is_file():
                return {"success": False, "error": f"Not a file: {path}"}

            # Check file size
            size_mb = file_path.stat().st_size / (1024 * 1024)
            if size_mb > max_size_mb:
                return {"success": False, "error": f"File too large: {size_mb:.2f}MB > {max_size_mb}MB"}

            content = file_path.read_text(encoding=encoding)

            return {
                "success": True,
                "path": str(file_path),
                "content": content,
                "size_bytes": file_path.stat().st_size,
                "lines": len(content.splitlines()),
            }

        except Exception as e:
            return {"success": False, "error": str(e)}

    def write_file(
        self,
        path: str,
        content: str,
        encoding: str = "utf-8",
        create_dirs: bool = True,
    ) -> dict[str, Any]:
        """
        Write content to a file.

        Args:
            path: File path (relative to base_path)
            content: Content to write
            encoding: File encoding
            create_dirs: Create parent directories if needed
        """
        try:
            file_path = self._resolve_path(path)

            if create_dirs:
                file_path.parent.mkdir(parents=True, exist_ok=True)

            file_path.write_text(content, encoding=encoding)

            return {
                "success": True,
                "path": str(file_path),
                "size_bytes": len(content.encode(encoding)),
            }

        except Exception as e:
            return {"success": False, "error": str(e)}

    def append_file(
        self,
        path: str,
        content: str,
        encoding: str = "utf-8",
    ) -> dict[str, Any]:
        """
        Append content to a file.

        Args:
            path: File path
            content: Content to append
            encoding: File encoding
        """
        try:
            file_path = self._resolve_path(path)

            with open(file_path, "a", encoding=encoding) as f:
                f.write(content)

            return {
                "success": True,
                "path": str(file_path),
                "appended_bytes": len(content.encode(encoding)),
            }

        except Exception as e:
            return {"success": False, "error": str(e)}

    def list_directory(
        self,
        path: str = ".",
        pattern: str | None = None,
        recursive: bool = False,
    ) -> dict[str, Any]:
        """
        List contents of a directory.

        Args:
            path: Directory path
            pattern: Glob pattern to filter files
            recursive: Search recursively
        """
        try:
            dir_path = self._resolve_path(path)

            if not dir_path.is_dir():
                return {"success": False, "error": f"Not a directory: {path}"}

            if pattern:
                if recursive:
                    files = list(dir_path.rglob(pattern))
                else:
                    files = list(dir_path.glob(pattern))
            else:
                if recursive:
                    files = list(dir_path.rglob("*"))
                else:
                    files = list(dir_path.iterdir())

            items = []
            for f in files:
                stat = f.stat()
                items.append({
                    "name": f.name,
                    "path": str(f.relative_to(self.base_path)),
                    "type": "directory" if f.is_dir() else "file",
                    "size_bytes": stat.st_size if f.is_file() else None,
                    "modified": datetime.fromtimestamp(stat.st_mtime, tz=timezone.utc).isoformat(),
                })

            return {
                "success": True,
                "path": str(dir_path),
                "items": items,
                "count": len(items),
            }

        except Exception as e:
            return {"success": False, "error": str(e)}

    def file_info(self, path: str) -> dict[str, Any]:
        """
        Get information about a file or directory.

        Args:
            path: File or directory path
        """
        try:
            file_path = self._resolve_path(path)

            if not file_path.exists():
                return {"success": False, "error": f"Path not found: {path}"}

            stat = file_path.stat()

            info = {
                "success": True,
                "path": str(file_path),
                "name": file_path.name,
                "type": "directory" if file_path.is_dir() else "file",
                "size_bytes": stat.st_size,
                "created": datetime.fromtimestamp(stat.st_ctime, tz=timezone.utc).isoformat(),
                "modified": datetime.fromtimestamp(stat.st_mtime, tz=timezone.utc).isoformat(),
                "accessed": datetime.fromtimestamp(stat.st_atime, tz=timezone.utc).isoformat(),
            }

            if file_path.is_file():
                info["extension"] = file_path.suffix

            return info

        except Exception as e:
            return {"success": False, "error": str(e)}

    def search_files(
        self,
        pattern: str,
        path: str = ".",
        content_pattern: str | None = None,
        max_results: int = 100,
    ) -> dict[str, Any]:
        """
        Search for files by name pattern and optionally content.

        Args:
            pattern: Glob pattern for file names
            path: Starting directory
            content_pattern: Pattern to search in file contents
            max_results: Maximum number of results
        """
        try:
            import re

            dir_path = self._resolve_path(path)
            files = list(dir_path.rglob(pattern))[:max_results]

            results = []
            for f in files:
                if f.is_file():
                    result = {
                        "path": str(f.relative_to(self.base_path)),
                        "size_bytes": f.stat().st_size,
                    }

                    if content_pattern:
                        try:
                            content = f.read_text(errors="ignore")
                            matches = list(re.finditer(content_pattern, content))
                            if matches:
                                result["content_matches"] = len(matches)
                                results.append(result)
                        except Exception:
                            pass
                    else:
                        results.append(result)

            return {
                "success": True,
                "pattern": pattern,
                "content_pattern": content_pattern,
                "results": results,
                "count": len(results),
            }

        except Exception as e:
            return {"success": False, "error": str(e)}

    def delete_file(self, path: str) -> dict[str, Any]:
        """
        Delete a file.

        Args:
            path: File path to delete
        """
        try:
            file_path = self._resolve_path(path)

            if not file_path.exists():
                return {"success": False, "error": f"File not found: {path}"}

            if not file_path.is_file():
                return {"success": False, "error": f"Not a file: {path}"}

            file_path.unlink()

            return {"success": True, "deleted": str(file_path)}

        except Exception as e:
            return {"success": False, "error": str(e)}

    def read_json(self, path: str) -> dict[str, Any]:
        """Read and parse a JSON file."""
        result = self.read_file(path)
        if not result.get("success"):
            return result

        try:
            data = json.loads(result["content"])
            return {
                "success": True,
                "path": result["path"],
                "data": data,
            }
        except json.JSONDecodeError as e:
            return {"success": False, "error": f"Invalid JSON: {e}"}

    def write_json(
        self,
        path: str,
        data: Any,
        indent: int = 2,
    ) -> dict[str, Any]:
        """Write data as JSON to a file."""
        try:
            content = json.dumps(data, indent=indent, default=str)
            return self.write_file(path, content)
        except Exception as e:
            return {"success": False, "error": str(e)}


# Tool definitions for Claude Agent SDK
FILE_TOOLS = [
    {
        "name": "read_file",
        "description": "Read contents of a file.",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "File path"},
                "encoding": {"type": "string", "description": "File encoding", "default": "utf-8"},
            },
            "required": ["path"],
        },
    },
    {
        "name": "write_file",
        "description": "Write content to a file.",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "File path"},
                "content": {"type": "string", "description": "Content to write"},
                "create_dirs": {"type": "boolean", "description": "Create parent directories", "default": True},
            },
            "required": ["path", "content"],
        },
    },
    {
        "name": "list_directory",
        "description": "List contents of a directory.",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Directory path", "default": "."},
                "pattern": {"type": "string", "description": "Glob pattern to filter"},
                "recursive": {"type": "boolean", "description": "Search recursively", "default": False},
            },
        },
    },
    {
        "name": "file_info",
        "description": "Get information about a file or directory.",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "File or directory path"},
            },
            "required": ["path"],
        },
    },
    {
        "name": "search_files",
        "description": "Search for files by name pattern and optionally content.",
        "input_schema": {
            "type": "object",
            "properties": {
                "pattern": {"type": "string", "description": "Glob pattern for file names"},
                "path": {"type": "string", "description": "Starting directory", "default": "."},
                "content_pattern": {"type": "string", "description": "Regex pattern to search in content"},
                "max_results": {"type": "integer", "description": "Maximum results", "default": 100},
            },
            "required": ["pattern"],
        },
    },
    {
        "name": "read_json",
        "description": "Read and parse a JSON file.",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "JSON file path"},
            },
            "required": ["path"],
        },
    },
    {
        "name": "write_json",
        "description": "Write data as JSON to a file.",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "File path"},
                "data": {"description": "Data to write as JSON"},
                "indent": {"type": "integer", "description": "Indentation spaces", "default": 2},
            },
            "required": ["path", "data"],
        },
    },
]


__all__ = ["FileTools", "FILE_TOOLS"]
