/**
 * Generic utility to transform snake_case object keys to camelCase at runtime.
 * This is the runtime equivalent of the CamelCasedPropertiesDeep type utility.
 */

// List of acronyms that should be preserved as uppercase in camelCase and lowercase in snake_case
const PRESERVED_ACRONYMS = ['PLP', 'PDP', 'SVG'];

/**
 * Converts a snake_case string to camelCase
 * Handles specific acronyms like PLP and PDP correctly
 */
export const toCamelCase = (str: string): string => {
  // Pre-process: convert all words that match the PRESERVED_ACRONYMS regex to uppercase
  let processedStr = str;
  for (const acronym of PRESERVED_ACRONYMS) {
    const regex = new RegExp(`_${acronym}_?`, 'gi');

    if (processedStr.match(regex)) {
      processedStr = processedStr.replace(regex, v =>
        v.endsWith('_') ? `${acronym}_` : `${acronym}`,
      );
    }
  }
  return processedStr.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
};

/**
 * Converts a camelCase string to snake_case
 * Handles consecutive capital letters correctly (e.g., "PDP" -> "pdp", not "p_d_p")
 * Preserves specific acronyms like PLP and PDP as lowercase in snake_case
 */
const toSnakeCase = (str: string) =>
  str
    .replace(/([A-Z])(?=[a-z])/g, '_$1')
    .replace(/([a-z])([A-Z])/g, '$1_$2')
    .toLowerCase()
    .replace(/^_/, '');

/**
 * Recursively transforms all object keys from snake_case to camelCase
 */
export const transformSnakeToCamel = (obj: unknown): unknown => {
  if (obj === null || obj === undefined) {
    return obj;
  }

  if (Array.isArray(obj)) {
    return obj.map(val => transformSnakeToCamel(val));
  }

  if (typeof obj === 'object') {
    const result: Record<string, unknown> = {};

    for (const [key, value] of Object.entries(obj)) {
      const camelKey = toCamelCase(key);
      result[camelKey] = transformSnakeToCamel(value);
    }

    return result;
  }

  return obj;
};

/**
 * Recursively transforms all object keys from camelCase to snake_case
 */
export const transformCamelToSnake = (obj: unknown): unknown => {
  if (obj === null || obj === undefined) {
    return obj;
  }

  if (Array.isArray(obj)) {
    return obj.map(transformCamelToSnake);
  }

  if (typeof obj === 'object') {
    const result: Record<string, unknown> = {};

    for (const [key, value] of Object.entries(obj)) {
      const snakeKey = toSnakeCase(key);
      result[snakeKey] = transformCamelToSnake(value);
    }

    return result;
  }

  return obj;
};
