'use strict';

const fs = require('fs');
const path = require('path');
const fg = require('fast-glob');
const { execSync } = require('child_process');
const { getContainerContext, resolveContainerPath, execContainerAction } = require('./container_bridge');

function resolvePath(workspace, p) {
  if (!p) return workspace;
  if (path.isAbsolute(p)) return p;
  return path.join(workspace, p);
}

function hasRg() {
  try {
    execSync('rg --version', { stdio: 'ignore' });
    return true;
  } catch (_) {
    return false;
  }
}

async function searchWorkspaceTool(workspace, args) {
  const root = resolvePath(workspace, args.root || '.');
  const mode = args.mode;
  const query = args.query || '';
  const useRegex = !!args.use_regex;
  const caseSensitive = !!args.case_sensitive;
  const maxResults = args.max_results || 20;
  const maxMatchesPerFile = args.max_matches_per_file || 3;
  const includeGlob = Array.isArray(args.include_glob) && args.include_glob.length ? args.include_glob : ['**/*'];
  const excludeGlob = Array.isArray(args.exclude_glob) ? args.exclude_glob : [];
  const maxFileSize = args.max_file_size || null;
  const ctx = getContainerContext();

  if (ctx) {
    const resolved = resolveContainerPath(workspace, args.root || '.', ctx);
    if (resolved.error) return { success: false, error: resolved.error };
    const resp = execContainerAction(ctx, 'search_workspace', {
      mode,
      query,
      use_regex: useRegex,
      case_sensitive: caseSensitive,
      max_results: maxResults,
      max_matches_per_file: maxMatchesPerFile,
      include_glob: includeGlob,
      exclude_glob: excludeGlob,
      max_file_size: maxFileSize,
      root: resolved.containerPath,
    }, null, resolved.containerPath);
    if (!resp.success) return { success: false, error: resp.error || '搜索失败' };
    return resp;
  }

  if (mode === 'file') {
    const files = await fg(includeGlob, { cwd: root, dot: true, ignore: excludeGlob, onlyFiles: true, absolute: true });
    const matcher = useRegex ? new RegExp(query, caseSensitive ? '' : 'i') : null;
    const matches = [];
    for (const file of files) {
      const name = path.basename(file);
      const hay = caseSensitive ? name : name.toLowerCase();
      const needle = caseSensitive ? query : query.toLowerCase();
      const ok = useRegex ? matcher.test(name) : hay.includes(needle);
      if (ok) {
        matches.push(file);
        if (matches.length >= maxResults) break;
      }
    }
    return { success: true, mode: 'file', root, query, matches };
  }

  if (mode === 'content') {
    if (hasRg()) {
      const argsList = ['--line-number', '--no-heading', '--color=never'];
      if (!useRegex) argsList.push('--fixed-strings');
      if (!caseSensitive) argsList.push('-i');
      if (maxMatchesPerFile) argsList.push(`--max-count=${maxMatchesPerFile}`);
      if (maxFileSize) argsList.push(`--max-filesize=${maxFileSize}`);
      for (const g of includeGlob) argsList.push('-g', g);
      for (const g of excludeGlob) argsList.push('-g', `!${g}`);
      argsList.push(query);
      argsList.push(root);
      let output = '';
      try {
        output = execSync(`rg ${argsList.map((a) => JSON.stringify(a)).join(' ')}`, { maxBuffer: 10 * 1024 * 1024 }).toString();
      } catch (err) {
        output = err.stdout ? err.stdout.toString() : '';
      }
      const lines = output.split(/\r?\n/).filter(Boolean);
      const files = new Map();
      for (const line of lines) {
        const [filePath, lineNum, ...rest] = line.split(':');
        const snippet = rest.join(':').trim();
        if (!files.has(filePath)) files.set(filePath, []);
        if (files.get(filePath).length < maxMatchesPerFile) {
          files.get(filePath).push({ line: Number(lineNum), snippet });
        }
        if (files.size >= maxResults) break;
      }
      const results = Array.from(files.entries()).map(([file, matches]) => ({ file, matches }));
      return { success: true, mode: 'content', root, query, results };
    }

    // fallback
    const files = await fg(includeGlob, { cwd: root, dot: true, ignore: excludeGlob, onlyFiles: true, absolute: true });
    const matcher = useRegex ? new RegExp(query, caseSensitive ? '' : 'i') : null;
    const results = [];
    for (const file of files) {
      if (maxFileSize) {
        try {
          const stat = fs.statSync(file);
          if (stat.size > maxFileSize) continue;
        } catch (_) {}
      }
      const content = fs.readFileSync(file, 'utf8');
      const lines = content.split(/\r?\n/);
      const matches = [];
      for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        const hay = caseSensitive ? line : line.toLowerCase();
        const needle = caseSensitive ? query : query.toLowerCase();
        const ok = useRegex ? matcher.test(line) : hay.includes(needle);
        if (ok) {
          matches.push({ line: i + 1, snippet: line.trim() });
          if (matches.length >= maxMatchesPerFile) break;
        }
      }
      if (matches.length) {
        results.push({ file, matches });
        if (results.length >= maxResults) break;
      }
    }
    return { success: true, mode: 'content', root, query, results };
  }

  return { success: false, error: '未知 search_workspace mode' };
}

module.exports = { searchWorkspaceTool };
