"""
GlobTool - Find files by glob pattern matching

Following OpenCode architecture, provides file discovery with:
- Glob pattern matching (e.g., **/*.py)
- Path traversal protection (SEC-003, SEC-007)
- .gitignore respect
- Sorted results
- Multiple pattern support
- Type-safe implementation
"""

from pathlib import Path
from typing import Any, List, Optional

from groknroll.tools.base_tool import BaseTool
from groknroll.tools.descriptions import get_enhanced_description
from groknroll.tools.validators import (
    validate_path_within_workspace,
    validate_pattern_input,
    PathValidationError,
)


class GlobTool(BaseTool):
    """
    Tool for finding files by glob patterns

    Accepts:
        pattern: str - Glob pattern (e.g., "**/*.py", "src/**/*.ts")
        max_results: int (optional) - Maximum number of results (default: 1000)

    Returns:
        List[str] - List of matching file paths (sorted)

    Raises:
        ValueError: If pattern is empty

    Example:
        tool = GlobTool()
        files = await tool.execute(pattern="**/*.py")
        for file in files:
            print(file)
    """

    def __init__(self, workspace_root: Optional[str] = None):
        """
        Initialize GlobTool

        Args:
            workspace_root: Optional root directory for pattern matching.
                           Defaults to current working directory.
        """
        self._workspace_root = Path(workspace_root) if workspace_root else Path.cwd()

    @property
    def name(self) -> str:
        """Tool identifier"""
        return "glob"

    @property
    def description(self) -> str:
        """Human-readable description"""
        return get_enhanced_description("glob", "Find files by glob pattern matching")

    def validate_params(self, **kwargs) -> dict[str, Any]:
        """
        Validate parameters before execution

        Args:
            **kwargs: Must contain 'pattern' parameter

        Returns:
            Validated parameters dict

        Raises:
            ValueError: If required parameters are missing or invalid
        """
        if "pattern" not in kwargs:
            raise ValueError("pattern parameter is required")

        # SEC-008: Use standardized validation
        validate_pattern_input(kwargs["pattern"])

        # SEC-007: Validate pattern doesn't escape workspace
        self._validate_pattern(kwargs["pattern"])

        # Validate max_results if provided
        if "max_results" in kwargs:
            max_results = kwargs["max_results"]
            if not isinstance(max_results, int):
                raise ValueError(
                    f"max_results must be an integer, got {type(max_results).__name__}"
                )
            if max_results <= 0:
                raise ValueError(f"max_results must be positive, got {max_results}")

        return kwargs

    def _validate_pattern(self, pattern: str) -> None:
        """
        Validate glob pattern doesn't attempt path escape.

        SEC-007: Glob tool path escape prevention.

        Args:
            pattern: The glob pattern to validate

        Raises:
            ValueError: If pattern attempts to escape workspace
        """
        # Check for patterns that start with / (absolute paths)
        if pattern.startswith('/'):
            raise ValueError(
                "Glob pattern cannot start with '/'. "
                "Use relative patterns within the workspace."
            )

        # Check for .. in patterns (directory traversal)
        if '..' in pattern:
            raise ValueError(
                "Glob pattern cannot contain '..'. "
                "Path traversal patterns are not allowed for security reasons."
            )

        # Check for null bytes
        if '\x00' in pattern:
            raise ValueError(
                "Glob pattern cannot contain null bytes."
            )

    async def execute(self, **kwargs) -> List[str]:
        """
        Execute glob pattern matching

        Args:
            **kwargs: Must contain 'pattern' parameter

        Returns:
            List[str] with matching file paths (sorted)

        Raises:
            ValueError: If pattern is invalid
        """
        # Validate parameters
        validated = self.validate_params(**kwargs)
        pattern = validated["pattern"]
        max_results = validated.get("max_results", 1000)

        # Find matching files
        matches = []
        try:
            for file_path in self._workspace_root.glob(pattern):
                if len(matches) >= max_results:
                    break

                # Only include files, not directories
                if file_path.is_file() and not self._should_ignore(file_path):
                    # SEC-003: Validate resolved path is within workspace
                    try:
                        resolved_path = file_path.resolve()
                        validate_path_within_workspace(resolved_path, self._workspace_root)
                        rel_path = resolved_path.relative_to(self._workspace_root.resolve())
                        matches.append(str(rel_path))
                    except (PathValidationError, ValueError):
                        # Skip files outside workspace (could be symlinks escaping)
                        continue

        except Exception:
            # If glob fails, return empty list
            return []

        # Sort results for consistency
        matches.sort()

        return matches

    def _should_ignore(self, file_path: Path) -> bool:
        """Check if file should be ignored based on common patterns"""
        ignore_patterns = {
            ".git",
            "__pycache__",
            "node_modules",
            ".venv",
            "venv",
            ".env",
            ".pytest_cache",
            ".mypy_cache",
            ".ruff_cache",
            "dist",
            "build",
            ".eggs",
            "*.egg-info",
        }

        path_str = str(file_path)
        for pattern in ignore_patterns:
            if pattern in path_str:
                return True

        return False
