import path from "node:path";
import { z } from "zod";
import { createToolFactory, PermissionLevel, ToolCategory } from "../types.js";
/**
 * Format file size into human-readable format (like ls -lh).
 *
 * @param bytes - File size in bytes
 * @returns Human-readable size string (e.g., "1.5K", "32M")
 */
function formatSize(bytes) {
    if (bytes < 1024)
        return `${bytes}`;
    if (bytes < 1024 * 1024)
        return `${(bytes / 1024).toFixed(1)}K`;
    if (bytes < 1024 * 1024 * 1024)
        return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
    return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}G`;
}
/**
 * Format date into ls -l style format.
 *
 * @param date - Date to format
 * @returns Formatted date string (e.g., "Jan 15 14:30")
 */
function formatDate(date) {
    const months = [
        "Jan",
        "Feb",
        "Mar",
        "Apr",
        "May",
        "Jun",
        "Jul",
        "Aug",
        "Sep",
        "Oct",
        "Nov",
        "Dec",
    ];
    const month = months[date.getMonth()];
    const day = date.getDate().toString().padStart(2, " ");
    const hours = date.getHours().toString().padStart(2, "0");
    const minutes = date.getMinutes().toString().padStart(2, "0");
    return `${month} ${day} ${hours}:${minutes}`;
}
/**
 * Format file metadata into ls -lh style output line.
 *
 * @param meta - File metadata object
 * @returns Formatted line (e.g., "-rw-r--r--  1 user  staff  1.5K Jan 15 14:30 file.ts")
 */
function formatMetadataLine(meta) {
    const type = meta.isDirectory ? "d" : "-";
    const perms = "rw-r--r--";
    const size = formatSize(meta.size);
    const date = formatDate(meta.mtime);
    const name = path.basename(meta.path);
    return `${type}${perms}  1 user  staff  ${size.padStart(6)} ${date} ${name}`;
}
/**
 * ls tool - List directory contents with metadata.
 *
 * Lists files and directories in a specified path, showing file sizes,
 * modification times, and whether each entry is a file or directory.
 * Uses AppShell for virtual file system support (APIs appear as .ts files).
 */
export const lsToolFactory = createToolFactory("ls", (services) => ({
    description: `
List directory contents with metadata (file sizes, modification times, file/directory types).

Use this tool when:
- Browsing a specific directory to see what files and folders exist
- Understanding directory structure
- Need file metadata (sizes, timestamps) to decide which files to read
- Initial exploration of an unfamiliar codebase
- Finding recently modified files in a directory

Returns formatted output similar to ls -lh. Call multiple times on subdirectories if you need to explore deeper.
`,
    category: ToolCategory.FILE,
    defaultPermission: PermissionLevel.ALLOW,
    inputSchema: z.object({
        path: z
            .string()
            .optional()
            .describe("Directory to list (defaults to current directory)"),
        includeHidden: z
            .boolean()
            .optional()
            .describe("Include hidden files (starting with .)"),
    }),
    readOnly: true,
    execute: async ({ path: dirPath = ".", includeHidden = false }) => {
        const appRoot = services.appShell.appRootDirPath;
        // Resolve requested path against app root
        const resolvedPath = path.resolve(appRoot, dirPath);
        // Security: Prevent directory traversal outside app root
        if (!resolvedPath.startsWith(appRoot)) {
            throw new Error(`Access denied: path '${dirPath}' is outside the application directory`);
        }
        // Build glob pattern for this directory
        const relativeDirPath = path.relative(appRoot, resolvedPath);
        const pattern = relativeDirPath ? `${relativeDirPath}/*` : "*";
        // Get files with metadata from AppShell
        const fileEntries = await services.appShell.listFiles([pattern], {
            includeMetadata: true,
            includeDirs: true,
            dot: includeHidden,
        });
        // Filter file entries to only include direct children of the target directory
        const directChildren = fileEntries.filter((entry) => {
            const entryDir = path.dirname(entry.path);
            return (entryDir === relativeDirPath || (entryDir === "." && !relativeDirPath));
        });
        // Combine and sort alphabetically by name
        const allEntries = directChildren.sort((a, b) => path.basename(a.path).localeCompare(path.basename(b.path)));
        // Format output
        if (allEntries.length === 0) {
            return { output: "" };
        }
        const lines = allEntries.map(formatMetadataLine);
        const totalSize = allEntries.reduce((sum, e) => sum + e.size, 0);
        const output = `total ${formatSize(totalSize)}\n${lines.join("\n")}`;
        return { output };
    },
    getSummary: (_input, output) => {
        // Count non-empty lines excluding the "total" line
        const lines = output.output
            .split("\n")
            .filter((l) => l.trim() && !l.startsWith("total"));
        const count = lines.length;
        return {
            output: `${count} item${count === 1 ? "" : "s"}`,
        };
    },
}));
//# sourceMappingURL=ls.js.map