/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * Escapes a string for use in a regular expression.
 */
export function escapeRegex(text: string): string {
  return text.replace(/[-[\]{}()*+?.,\\^$|#\s"]/g, '\\$&');
}

/**
 * Basic validation for regular expressions to prevent common ReDoS patterns.
 * This is a heuristic check and not a substitute for a full ReDoS scanner.
 */
export function isSafeRegExp(pattern: string): boolean {
  try {
    // 1. Ensure it's a valid regex
    new RegExp(pattern);
  } catch {
    return false;
  }

  // 2. Limit length to prevent extremely long regexes
  if (pattern.length > 2048) {
    return false;
  }

  // 3. Heuristic: Check for nested quantifiers which are a primary source of ReDoS.
  // Examples: (a+)+, (a|b)*, (.*)*, ([a-z]+)+
  // We look for a group (...) followed by a quantifier (+, *, or {n,m})
  // where the group itself contains a quantifier.
  // This matches a '(' followed by some content including a quantifier, then ')',
  // followed by another quantifier.
  const nestedQuantifierPattern = /\([^)]*[*+?{].*\)[*+?{]/;
  if (nestedQuantifierPattern.test(pattern)) {
    return false;
  }

  return true;
}

/**
 * Builds a list of args patterns for policy matching.
 *
 * This function handles the transformation of command prefixes and regexes into
 * the internal argsPattern representation used by the PolicyEngine.
 *
 * @param argsPattern An optional raw regex string for arguments.
 * @param commandPrefix An optional command prefix (or list of prefixes) to allow.
 * @param commandRegex An optional command regex string to allow.
 * @returns An array of string patterns (or undefined) for the PolicyEngine.
 */
export function buildArgsPatterns(
  argsPattern?: string,
  commandPrefix?: string | string[],
  commandRegex?: string,
): Array<string | undefined> {
  if (commandPrefix) {
    const prefixes = Array.isArray(commandPrefix)
      ? commandPrefix
      : [commandPrefix];

    return prefixes.map((prefix) => {
      // JSON.stringify safely encodes the prefix in quotes.
      // We remove ONLY the trailing quote to match it as an open prefix string.
      const encodedPrefix = JSON.stringify(prefix);
      const openQuotePrefix = encodedPrefix.substring(
        0,
        encodedPrefix.length - 1,
      );

      // Escape the exact JSON literal segment we expect to see
      const matchSegment = escapeRegex(`"command":${openQuotePrefix}`);

      // We allow [\s], ["], or the specific sequence [\"] (for escaped quotes
      // in JSON). We do NOT allow generic [\\], which would match "git\status"
      // -> "gitstatus".
      return `${matchSegment}(?:[\\s"]|\\\\")`;
    });
  }

  if (commandRegex) {
    return [`"command":"${commandRegex}`];
  }

  return [argsPattern];
}

/**
 * Builds a regex pattern to match a specific parameter and value in tool arguments.
 * This is used to narrow tool approvals to specific parameters.
 *
 * @param paramName The name of the parameter.
 * @param value The value to match.
 * @returns A regex string that matches "<paramName>":<value> in a JSON string.
 */
export function buildParamArgsPattern(
  paramName: string,
  value: unknown,
): string {
  const encodedValue = JSON.stringify(value);
  // We wrap the JSON string in escapeRegex and prepend/append \\0 to explicitly
  // match top-level JSON properties generated by stableStringify, preventing
  // argument injection bypass attacks.
  return `\\\\0${escapeRegex(`"${paramName}":${encodedValue}`)}\\\\0`;
}

/**
 * Builds a regex pattern to match a specific file path in tool arguments.
 * This is used to narrow tool approvals for edit tools to specific files.
 *
 * @param filePath The relative path to the file.
 * @returns A regex string that matches "file_path":"<path>" in a JSON string.
 */
export function buildFilePathArgsPattern(filePath: string): string {
  return buildParamArgsPattern('file_path', filePath);
}

/**
 * Builds a regex pattern to match a specific directory path in tool arguments.
 * This is used to narrow tool approvals for list_directory tool.
 *
 * @param dirPath The path to the directory.
 * @returns A regex string that matches "dir_path":"<path>" in a JSON string.
 */
export function buildDirPathArgsPattern(dirPath: string): string {
  return buildParamArgsPattern('dir_path', dirPath);
}

/**
 * Builds a regex pattern to match a specific "pattern" in tool arguments.
 * This is used to narrow tool approvals for search tools like glob/grep to specific patterns.
 *
 * @param pattern The pattern to match.
 * @returns A regex string that matches "pattern":"<pattern>" in a JSON string.
 */
export function buildPatternArgsPattern(pattern: string): string {
  return buildParamArgsPattern('pattern', pattern);
}
