"""
Copyright (C) 2024-2026 Mo Zhou <lumin@debian.org>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
"""

import difflib
import os
import pty
import re
import select
import shlex
import subprocess
import tempfile
from collections import deque

from rich.console import Console
from rich.live import Live
from rich.panel import Panel
from rich.text import Text

from .base import Tool, _diff_stat, _short, render_diff


class FileFinder(Tool):
    """Tool to find files and directories (wraps the Unix find command)."""

    name = "file_finder"
    description = (
        "Search for files and directories using the Unix find "
        "command. Supports filtering by name pattern, file type, "
        "and max depth. An extra_args parameter is available for "
        "any additional find options."
    )

    # Flags that can modify or execute on the filesystem
    _DANGEROUS_FLAGS = {
        "-delete",
        "-exec",
        "-execdir",
        "-ok",
        "-okdir",
    }

    def needs_confirmation(self, args_dict: dict) -> tuple:
        extra = args_dict.get("extra_args", "") or ""

        tokens = shlex.split(extra)
        found = [t for t in tokens if t in self._DANGEROUS_FLAGS]
        if found:
            flags = ", ".join(found)
            return True, f"Dangerous find flag(s) detected: {flags}"
        return False, ""

    def summary(self, args_dict: dict) -> str:
        path = args_dict.get("path", ".")
        name = args_dict.get("name")
        return f"find {_short(name)} in {path}" if name else f"find in {path}"

    def __call__(
        self,
        path: str = ".",
        name: str = None,
        type: str = None,
        maxdepth: int = None,
        extra_args: str = None,
    ) -> str:
        try:
            path = os.path.expanduser(path)
            if not os.path.exists(path):
                return f"Error: '{path}' does not exist."

            cmd = ["find", path]

            if maxdepth is not None:
                cmd.extend(["-maxdepth", str(int(maxdepth))])
            if type is not None:
                cmd.extend(["-type", str(type)])
            if name is not None:
                cmd.extend(["-name", str(name)])
            if extra_args is not None:
                cmd.extend(shlex.split(extra_args))

            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            if result.returncode != 0 and result.stderr.strip():
                return f"Error: {result.stderr.strip()}"
            return result.stdout if result.stdout else "(no results)"
        except subprocess.TimeoutExpired:
            return "Error: find command timed out after 30 seconds."
        except Exception as e:
            return f"Error: {str(e)}"

    parameters = {
        "type": "object",
        "properties": {
            "path": {
                "type": "string",
                "description": "Starting directory for the " "search. Defaults to '.'.",
            },
            "name": {
                "type": "string",
                "description": "Filename pattern to match "
                "(supports shell wildcards, e.g. "
                "'*.py'). Maps to find -name.",
            },
            "type": {
                "type": "string",
                "enum": ["f", "d", "l"],
                "description": "File type filter: 'f' for "
                "regular files, 'd' for "
                "directories, 'l' for symbolic "
                "links.",
            },
            "maxdepth": {
                "type": "integer",
                "description": "Maximum directory depth to "
                "descend. 0 means only the "
                "starting path itself.",
            },
            "extra_args": {
                "type": "string",
                "description": "Additional arguments passed "
                "directly to find (e.g. "
                "'-mtime -1 -size +1M').",
            },
        },
        "required": [],
    }
