/**
 * ============================================================
 *  src/tools/glob.ts —— Glob 工具（按文件名模式匹配）
 * ------------------------------------------------------------
 *  对应 kakadeai 主仓库的 GlobTool。
 *  实现用 fast-glob（npm 包），结果按 mtime 升序排列（旧文件在前）。
 *  如果结果过多，从尾部截断（保留旧文件，丢弃新文件）。
 * ============================================================
 */
import { stat } from 'node:fs/promises';
import { isAbsolute, resolve } from 'node:path';
import fg from 'fast-glob';
import { z } from 'zod';
import { getWorkingDir } from '../../bootstrap/workingDir.js';
import { DEFAULT_MAX_RESULT_SIZE_CHARS } from '../types.js';
import { toToolParameters } from '../../utils/zodToJson.js';
// ---------------- 1. Zod 输入 schema ----------------
const inputSchema = z.object({
    pattern: z
        .string()
        .min(1)
        .describe('glob 模式，例如 "**/*.ts" 或 "src/components/**/*.tsx"'),
    path: z
        .string()
        .optional()
        .describe('搜索的根目录（默认当前工作目录）；省略时不要传 "undefined" 字符串'),
});
// ---------------- 2. JSON Schema（由 Zod 自动派生） ----------------
const parameters = toToolParameters(inputSchema);
// ---------------- 3. Description（搬自 kakadeai/tools/GlobTool/prompt.ts 的 DESCRIPTION） ----------------
const description = `- Fast file pattern matching tool that works with any codebase size
- Supports glob patterns like "**/*.js" or "src/**/*.ts"
- Returns matching file paths sorted by modification time (oldest first)
- Use this tool when you need to find files by name patterns
- When you need to do an open ended search that may require multiple rounds, prefer the Grep tool for content search`;
// ---------------- 4. call() ----------------
async function call(input) {
    const cwd = input.path ? resolve(input.path) : getWorkingDir();
    // 跨平台：fast-glob 强制要求 pattern 用正斜杠。
    // Windows 用户/模型可能传 "src\**\*.ts"，这里统一替换。
    // （cwd 用原生路径没问题；fast-glob 内部会处理）
    const pattern = input.pattern.replace(/\\/g, '/');
    // fast-glob 自带 ignore 一部分（node_modules 之类还是要显式排除）
    let matches;
    try {
        matches = await fg(pattern, {
            cwd,
            dot: true,
            onlyFiles: true,
            followSymbolicLinks: false,
            // 默认排除一些噪音目录；如果用户的 pattern 显式指了它们，这里也不会盖
            ignore: ['**/node_modules/**', '**/.git/**', '**/dist/**'],
            absolute: false,
        });
    }
    catch (e) {
        return { ok: false, error: `glob 失败：${e.message}` };
    }
    if (matches.length === 0) {
        return { ok: true, content: `(no files matched pattern "${pattern}" in ${cwd})` };
    }
    // 按 mtime 升序排：旧文件在前（与 Grep 的新在前形成互补锁定模板）
    const withMtime = await Promise.all(matches.map(async (rel) => {
        const abs = isAbsolute(rel) ? rel : resolve(cwd, rel);
        try {
            const st = await stat(abs);
            return { path: rel, mtime: st.mtimeMs };
        }
        catch {
            return { path: rel, mtime: 0 };
        }
    }));
    withMtime.sort((a, b) => a.mtime - b.mtime);
    // 输出：每行一个相对路径
    let content = withMtime.map((m) => m.path).join('\n');
    // 超条数截断：保留旧文件（头部），丢弃新文件（尾部）
    if (content.length > DEFAULT_MAX_RESULT_SIZE_CHARS) {
        content =
            content.slice(0, DEFAULT_MAX_RESULT_SIZE_CHARS) +
                `\n\n... (共 ${withMtime.length} 个文件，输出超过 ${DEFAULT_MAX_RESULT_SIZE_CHARS} 字符，已截断尾部新文件)`;
    }
    return {
        ok: true,
        content: `${content}\n\n(共 ${withMtime.length} 个文件，按修改时间升序/旧在前)`,
    };
}
// ---------------- 5. 导出 ----------------
export const globTool = {
    name: 'Glob',
    description,
    inputSchema,
    parameters,
    isReadOnly: true,
    isConcurrencySafe: true,
    maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
    call,
};
