/**
 * Glob tool — find files by pattern matching.
 */

import { readdirSync, statSync } from 'fs';
import { join, resolve, normalize, relative } from 'path';

const MAX_RESULTS = 1000;

export const definition = {
  name: 'Glob',
  description: 'Fast file pattern matching. Returns matching file paths sorted by modification time.',
  input_schema: {
    type: 'object',
    properties: {
      pattern: { type: 'string', description: 'Glob pattern to match (e.g., "**/*.js", "src/**/*.ts")' },
      path: { type: 'string', description: 'Directory to search in (defaults to workspace root)' }
    },
    required: ['pattern']
  }
};

/**
 * Convert a simple glob pattern to a regex.
 * Supports: * (any segment), ** (any path), ? (single char)
 */
function globToRegex(pattern) {
  let re = '';
  let i = 0;
  while (i < pattern.length) {
    const ch = pattern[i];
    if (ch === '*' && pattern[i + 1] === '*') {
      // ** matches any path depth
      re += '.*';
      i += 2;
      if (pattern[i] === '/' || pattern[i] === '\\') i++; // skip separator after **
    } else if (ch === '*') {
      re += '[^/\\\\]*';
      i++;
    } else if (ch === '?') {
      re += '[^/\\\\]';
      i++;
    } else if (ch === '.') {
      re += '\\.';
      i++;
    } else if ('[({+|^$}'.includes(ch)) {
      re += '\\' + ch;
      i++;
    } else {
      re += ch;
      i++;
    }
  }
  return new RegExp('^' + re + '$', 'i');
}

/**
 * Recursively list files in a directory.
 */
function walkDir(dir, maxDepth = 20, depth = 0) {
  if (depth > maxDepth) return [];
  const results = [];
  let entries;
  try {
    entries = readdirSync(dir, { withFileTypes: true });
  } catch {
    return [];
  }
  for (const entry of entries) {
    if (entry.name.startsWith('.')) continue; // Skip hidden
    const full = join(dir, entry.name);
    if (entry.isDirectory()) {
      if (entry.name === 'node_modules' || entry.name === '.git') continue;
      results.push(...walkDir(full, maxDepth, depth + 1));
    } else if (entry.isFile()) {
      results.push(full);
    }
  }
  return results;
}

export async function execute(input, context) {
  const { pattern, path: searchPath } = input;

  if (!pattern) return { content: 'Error: pattern is required', is_error: true };

  const baseDir = searchPath
    ? resolve(normalize(searchPath))
    : context.workspaceRoot;

  // Path validation
  const wsNorm = resolve(normalize(context.workspaceRoot));
  const agNorm = resolve(normalize(context.agentRoot));
  const baseDirNorm = resolve(normalize(baseDir));
  if (!baseDirNorm.startsWith(wsNorm) && !baseDirNorm.startsWith(agNorm)) {
    return { content: `Error: Path "${baseDir}" is outside allowed directories`, is_error: true };
  }

  try {
    const regex = globToRegex(pattern);
    const allFiles = walkDir(baseDir);

    // Match relative paths against pattern
    const matches = allFiles
      .filter(f => {
        const rel = relative(baseDir, f).replace(/\\/g, '/');
        return regex.test(rel);
      })
      .map(f => {
        try {
          const s = statSync(f);
          return { path: f, mtime: s.mtimeMs };
        } catch {
          return { path: f, mtime: 0 };
        }
      })
      .sort((a, b) => b.mtime - a.mtime)
      .slice(0, MAX_RESULTS);

    if (matches.length === 0) {
      return { content: `No files matching "${pattern}" found in ${baseDir}`, is_error: false };
    }

    const result = matches.map(m => m.path).join('\n');
    const suffix = matches.length >= MAX_RESULTS ? `\n\n[Results limited to ${MAX_RESULTS}]` : '';
    return { content: result + suffix, is_error: false };
  } catch (err) {
    return { content: `Error: ${err.message}`, is_error: true };
  }
}
