import { getBasename, stripWrappers } from '../shell.ts';

import { hasRecursiveForceFlags } from './rm-flags.ts';

const REASON_FIND_DELETE = 'find -delete permanently removes files. Use -print first to preview.';

export function analyzeFind(tokens: readonly string[]): string | null {
  // Check for -delete outside of -exec/-execdir blocks
  if (findHasDelete(tokens.slice(1))) {
    return REASON_FIND_DELETE;
  }

  // Check all -exec and -execdir blocks for dangerous commands
  for (let i = 0; i < tokens.length; i++) {
    const token = tokens[i];
    if (token === '-exec' || token === '-execdir') {
      const execTokens = tokens.slice(i + 1);
      const semicolonIdx = execTokens.indexOf(';');
      const plusIdx = execTokens.indexOf('+');
      // If no terminator found, shell-quote may have parsed it as an operator
      // In that case, treat the rest of the tokens as the exec command
      const endIdx =
        semicolonIdx !== -1 && plusIdx !== -1
          ? Math.min(semicolonIdx, plusIdx)
          : semicolonIdx !== -1
            ? semicolonIdx
            : plusIdx !== -1
              ? plusIdx
              : execTokens.length; // No terminator - use all remaining tokens

      let execCommand = execTokens.slice(0, endIdx);
      // Strip wrappers (env, sudo, command)
      execCommand = stripWrappers(execCommand);
      if (execCommand.length > 0) {
        let head = getBasename(execCommand[0] ?? '');
        // Handle busybox wrapper
        if (head === 'busybox' && execCommand.length > 1) {
          execCommand = execCommand.slice(1);
          head = getBasename(execCommand[0] ?? '');
        }
        if (head === 'rm' && hasRecursiveForceFlags(execCommand)) {
          return 'find -exec rm -rf is dangerous. Use explicit file list instead.';
        }
      }
    }
  }

  return null;
}

/**
 * Check if find command has -delete action (not as argument to another option).
 * Handles cases like "find -name -delete" where -delete is a filename pattern.
 */
export function findHasDelete(tokens: readonly string[]): boolean {
  let i = 0;
  let insideExec = false;
  let execDepth = 0;

  while (i < tokens.length) {
    const token = tokens[i];
    if (!token) {
      i++;
      continue;
    }

    // Track -exec/-execdir blocks
    if (token === '-exec' || token === '-execdir') {
      insideExec = true;
      execDepth++;
      i++;
      continue;
    }

    // End of -exec block
    if (insideExec && (token === ';' || token === '+')) {
      execDepth--;
      if (execDepth === 0) {
        insideExec = false;
      }
      i++;
      continue;
    }

    // Skip -delete inside -exec blocks
    if (insideExec) {
      i++;
      continue;
    }

    // Options that take an argument - skip the next token
    if (
      token === '-name' ||
      token === '-iname' ||
      token === '-path' ||
      token === '-ipath' ||
      token === '-regex' ||
      token === '-iregex' ||
      token === '-type' ||
      token === '-user' ||
      token === '-group' ||
      token === '-perm' ||
      token === '-size' ||
      token === '-mtime' ||
      token === '-ctime' ||
      token === '-atime' ||
      token === '-newer' ||
      token === '-printf' ||
      token === '-fprint' ||
      token === '-fprintf'
    ) {
      i += 2; // Skip option and its argument
      continue;
    }

    // Found -delete outside of -exec and not as an argument
    if (token === '-delete') {
      return true;
    }

    i++;
  }

  return false;
}
