// @lifecycle canonical - Utility barrel plus compatibility exports for frameworks and gates.
/**
 * Utility Functions Module
 * Consolidates all utility functions used across the application
 */

// Re-export existing utilities
export * from './errorHandling.js';
export * from './jsonUtils.js';
export * from './chainUtils.js';
export * from './constants.js';
export * from './yaml/index.js';
export * from './resource-loader-types.js';
export * from './file-transactions.js';
export * from './usage-tracker.js';

// Template system removed - functionality moved to methodology guides

// Additional utilities extracted from index.ts

/**
 * Clear the require cache for prompt-related modules
 */
export function clearRequireCache(): void {
  // Get all cached module paths
  const cachedModulePaths = Object.keys(require.cache);

  // Filter for prompt files and configs
  const promptPaths = cachedModulePaths.filter(
    (modulePath) => modulePath.includes('prompts/') || modulePath.endsWith('.md')
  );

  // Clear them from cache
  promptPaths.forEach((modulePath) => {
    delete require.cache[modulePath];
  });

  // Use stderr to avoid corrupting STDIO protocol
  console.error(`Cleared ${promptPaths.length} prompt-related modules from require cache`);
}

/**
 * Force garbage collection if available
 */
export function forceGarbageCollection(): boolean {
  if (global.gc) {
    try {
      global.gc();
      return true;
    } catch (gcError) {
      console.warn('Could not force garbage collection:', gcError);
      return false;
    }
  }
  return false;
}

/**
 * Delay execution for a specified number of milliseconds
 */
export function delay(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

/**
 * Create a unique identifier
 */
export function createUniqueId(prefix: string = ''): string {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substr(2, 9);
  return prefix ? `${prefix}_${timestamp}_${random}` : `${timestamp}_${random}`;
}

/**
 * Safely stringify an object, handling circular references
 */
export function safeStringify(obj: any, indent: number = 0): string {
  try {
    return JSON.stringify(obj, null, indent);
  } catch (error) {
    // Handle circular references
    const seen = new Set();
    return JSON.stringify(
      obj,
      (key, value) => {
        if (typeof value === 'object' && value !== null) {
          if (seen.has(value)) {
            return '[Circular]';
          }
          seen.add(value);
        }
        return value;
      },
      indent
    );
  }
}

/**
 * Check if a string is valid JSON
 */
export function isValidJson(str: string): boolean {
  try {
    JSON.parse(str);
    return true;
  } catch {
    return false;
  }
}

/**
 * Escape JSON string for safe processing through Nunjucks templates
 * Replaces problematic characters that Nunjucks might interpret as template syntax
 */
export function escapeJsonForNunjucks(jsonStr: string): string {
  return jsonStr
    .replace(/\{\{/g, '\\{\\{') // Escape Nunjucks variable syntax
    .replace(/\}\}/g, '\\}\\}') // Escape Nunjucks variable syntax
    .replace(/\{%/g, '\\{\\%') // Escape Nunjucks tag syntax
    .replace(/%\}/g, '\\%\\}') // Escape Nunjucks tag syntax
    .replace(/\{#/g, '\\{\\#') // Escape Nunjucks comment syntax
    .replace(/#\}/g, '\\#\\}'); // Escape Nunjucks comment syntax
}

/**
 * Unescape JSON string after Nunjucks processing
 * Reverses the escaping applied by escapeJsonForNunjucks
 */
export function unescapeJsonFromNunjucks(escapedStr: string): string {
  return escapedStr
    .replace(/\\{\\{/g, '{{') // Restore Nunjucks variable syntax
    .replace(/\\}\\}/g, '}}') // Restore Nunjucks variable syntax
    .replace(/\\{\\%/g, '{%') // Restore Nunjucks tag syntax
    .replace(/\\%\\}/g, '%}') // Restore Nunjucks tag syntax
    .replace(/\\{\\#/g, '{#') // Restore Nunjucks comment syntax
    .replace(/\\#\\}/g, '#}'); // Restore Nunjucks comment syntax
}

/**
 * Safely parse JSON with Nunjucks compatibility
 * Attempts to parse JSON, applying escaping if necessary
 */
export function safeJsonParse(jsonStr: string): { success: boolean; data?: any; error?: string } {
  try {
    // First try direct parsing
    const data = JSON.parse(jsonStr);
    return { success: true, data };
  } catch (directError) {
    try {
      // If direct parsing fails, try with unescaping
      const unescaped = unescapeJsonFromNunjucks(jsonStr);
      const data = JSON.parse(unescaped);
      return { success: true, data };
    } catch (unescapeError) {
      return {
        success: false,
        error: `JSON parsing failed: ${directError instanceof Error ? directError.message : String(directError)}`,
      };
    }
  }
}

/**
 * Truncate text to a maximum length
 */
export function truncateText(text: string, maxLength: number, suffix: string = '...'): string {
  if (text.length <= maxLength) {
    return text;
  }
  return text.substring(0, maxLength - suffix.length) + suffix;
}

/**
 * Convert camelCase to kebab-case
 */
export function camelToKebab(str: string): string {
  return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
}

/**
 * Convert kebab-case to camelCase
 */
export function kebabToCamel(str: string): string {
  return str.replace(/-([a-z])/g, (g) => (g[1] ? g[1].toUpperCase() : ''));
}

/**
 * Validate email format
 */
export function isValidEmail(email: string): boolean {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

/**
 * Parse command line arguments into key-value pairs
 */
export function parseArgs(args: string[]): Record<string, string> {
  const parsed: Record<string, string> = {};

  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    if (!arg?.startsWith('--')) {
      continue;
    }

    const [key, value] = arg.split('=');
    const normalizedKey = key?.substring(2);
    if (!normalizedKey) {
      continue;
    }

    if (value !== undefined) {
      parsed[normalizedKey] = value;
    } else if (i + 1 < args.length) {
      const nextArg = args[i + 1];
      if (nextArg !== undefined && !nextArg.startsWith('--')) {
        parsed[normalizedKey] = nextArg;
        i++;
        continue;
      }
      parsed[normalizedKey] = 'true';
    } else {
      parsed[normalizedKey] = 'true';
    }
  }

  return parsed;
}

/**
 * Mock logger for testing purposes
 * Uses stderr to avoid corrupting STDIO protocol
 */
export class MockLogger {
  info(message: string, ...args: any[]): void {
    console.error(`[INFO] ${message}`, ...args);
  }

  error(message: string, ...args: any[]): void {
    console.error(`[ERROR] ${message}`, ...args);
  }

  warn(message: string, ...args: any[]): void {
    console.warn(`[WARN] ${message}`, ...args);
  }

  debug(message: string, ...args: any[]): void {
    console.error(`[DEBUG] ${message}`, ...args);
  }

  setTransport(_transport: string): void {
    // Mock implementation - no-op
  }

  setDebugEnabled(_enabled: boolean): void {
    // Mock implementation - no-op
  }

  logStartupInfo(transport: string, config: any): void {
    this.info(`Mock startup - Transport: ${transport}`);
    this.debug('Mock config:', JSON.stringify(config, null, 2));
  }

  logMemoryUsage(): void {
    this.info(`Mock memory usage: ${JSON.stringify(process.memoryUsage())}`);
  }
}
