/**
 * 蛇形命名(snake_case)转驼峰命名(camelCase)工具函数
 */

// 蛇形转驼峰
function snakeToCamel(str: string): string {
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
}

// 驼峰转蛇形
function camelToSnake(str: string): string {
  return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
}

/**
 * 深层递归转换对象键名
 * @param obj 输入对象
 * @param reverse 是否反向转换（驼峰转蛇形）
 * @returns 转换后的对象
 */
function convertObjectKeys<TOutput = object, TInput extends object = object>(
  obj: TInput,
  reverse: boolean = false
): TOutput {
  if (obj === null || obj === undefined) {
    return obj as unknown as TOutput;
  }

  if (Array.isArray(obj)) {
    return obj.map(item => convertObjectKeys(item as object, reverse)) as unknown as TOutput;
  }

  if (typeof obj !== 'object' || obj instanceof Date) {
    return obj as unknown as TOutput;
  }

  const result: Record<string, unknown> = {};
  const convertKey = reverse ? camelToSnake : snakeToCamel;

  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      const convertedKey = convertKey(key);
      const value = (obj as Record<string, unknown>)[key];
      if (value !== null && value !== undefined && typeof value === 'object') {
        result[convertedKey] = convertObjectKeys(value as object, reverse);
      } else {
        result[convertedKey] = value;
      }
    }
  }

  return result as TOutput;
}

/**
 * snake_case转camelCase - 支持两个泛型参数
 * @param obj 输入对象（类型为TInput）
 * @returns 转换后的camelCase对象（类型为TOutput）
 */
export function snakeToCamelCase<TOutput = object, TInput extends object = object>(obj: TInput): TOutput {
  return convertObjectKeys<TOutput, TInput>(obj, false);
}

/**
 * camelCase转snake_case - 支持两个泛型参数
 * @param obj 输入对象（类型为TInput）
 * @returns 转换后的snake_case对象（类型为TOutput）
 */
export function camelToSnakeCase<TOutput = object, TInput extends object = object>(obj: TInput): TOutput {
  return convertObjectKeys<TOutput, TInput>(obj, true);
}