/*
 * @Author: 赵伟
 * @Date: 2024-03-25 13:52:54
 * @Description: 工具类
 */

import G6 from '@antv/g6';

// 生成 8 位随机数
export function s8() {
  return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
}

export function getNameByCode(list: any[], code: any) {
  let name = '';
  list.forEach((item) => {
    if (item.dictValue === code) name = item.dictLabel;
  });
  return name;
}

// 解析 json 字符串
export function parseJsonText(text?: string | null): any | null {
  if (text === undefined || text === null || text === '') {
    return null;
  }
  try {
    return JSON.parse(text);
  } catch (error) {
    return null;
  }
}

// 判断是否为一般对象
function isPlainObject(value: any) {
  if (value === null || typeof value !== 'object') return false;
  let proto = Object.getPrototypeOf(value);
  while (proto !== null) {
    if (proto.constructor && proto.constructor !== Object) return false;
    proto = Object.getPrototypeOf(proto);
  }
  return true;
}

// underscore to camelCase
export function underscoreToCamelCase(obj: Record<string, any>) {
  if (!isPlainObject(obj)) {
    return obj;
  }
  const newObj: Record<string, any> = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const newKey = key.replace(/([-_][a-z])/gi, function ($1) {
        return $1.toUpperCase().replace('[-_]', '').replace('_', '');
      });
      let value = obj[key];
      if (Array.isArray(value)) {
        value = value.map((item) => underscoreToCamelCase(item));
      } else if (isPlainObject(value)) {
        value = underscoreToCamelCase(value);
      }
      newObj[newKey] = value;
    }
  }
  return newObj;
}

// camelCase to underscore
export function camelCaseToUnderscore(obj: Record<string, any>) {
  if (!isPlainObject(obj)) {
    return obj;
  }
  const newObj: Record<string, any> = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const newKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
      let value = obj[key];
      if (Array.isArray(value)) {
        value = value.map((item) => camelCaseToUnderscore(item));
      } else if (isPlainObject(value)) {
        value = camelCaseToUnderscore(value);
      }
      newObj[newKey] = value;
    }
  }
  return newObj;
}

// null to undefined
export function nullToUndefined(obj: Record<string, any>) {
  if (!isPlainObject(obj)) {
    return obj;
  }
  const newObj: Record<string, any> = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const value = obj[key];
      if (value === null) {
        newObj[key] = undefined;
      } else if (Array.isArray(value)) {
        newObj[key] = value.map((item) => nullToUndefined(item));
      } else if (isPlainObject(value)) {
        newObj[key] = nullToUndefined(value);
      } else {
        newObj[key] = value;
      }
    }
  }
  return newObj;
}

// undefined to null
export function undefinedToNull(obj: Record<string, any>) {
  if (!isPlainObject(obj)) {
    return obj;
  }
  const newObj: Record<string, any> = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const value = obj[key];
      if (value === undefined) {
        newObj[key] = null;
      } else if (Array.isArray(value)) {
        newObj[key] = value.map((item) => undefinedToNull(item));
      } else if (isPlainObject(value)) {
        newObj[key] = undefinedToNull(value);
      } else {
        newObj[key] = value;
      }
    }
  }
  return newObj;
}

/**
 * Changes the property names of an object based on a mapping provided.
 *
 * @param obj - The object whose property names need to be changed.
 * @param mapping - The mapping of old property names to new property names.
 * @return The object with the changed property names.
 */
export function changePropertyName(obj: Record<string, any>, mapping: Record<string, string>) {
  if (!isPlainObject(obj)) {
    return obj;
  }
  const newObj: Record<string, any> = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      let value = obj[key];
      const newKey = mapping.hasOwnProperty(key) ? mapping[key] : key;
      if (Array.isArray(value)) {
        value = value.map((item) => changePropertyName(item, mapping));
      } else if (isPlainObject(value)) {
        value = changePropertyName(value, mapping);
      }
      newObj[newKey] = value;
    }
  }
  return newObj;
}

/**
 * 计算能显示的字符串
 * @param {string} str 要裁剪的字符串
 * @param {number} maxWidth 最大宽度
 * @param {number} fontSize 字体大小
 * @return {string} 处理后的字符串
 */
export const fittingString = (str: string, maxWidth: number, fontSize: number): string => {
  if (!str) {
    return '';
  }
  const ellipsis = '...';
  const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
  let currentWidth = 0;
  let res = str;
  const pattern = new RegExp('[\u4E00-\u9FA5]+'); // distinguish the Chinese charactors and letters
  str.split('').forEach((letter, i) => {
    if (currentWidth > maxWidth - ellipsisLength) return;
    if (pattern.test(letter)) {
      // Chinese charactors
      currentWidth += fontSize;
    } else {
      // get the width of single letter according to the fontSize
      currentWidth += G6.Util.getLetterWidth(letter, fontSize);
    }
    if (currentWidth > maxWidth - ellipsisLength) {
      res = `${str.substring(0, i)}${ellipsis}`;
    }
  });
  return res;
};

/**
 * Checks if a given string is empty, undefined, or null.
 *
 * @param {any} str - the string to be checked
 * @return {boolean} true if the string is empty, undefined, or null, false otherwise
 */
export const isEmptyString = (str: any): boolean => {
  return str === '' || str === undefined || str === null;
};

/**
 * 获取 git 仓库的 url
 *
 * @param {string} url - the url of the git repository
 * @param {string} branch - the branch of the repository
 * @return {string} the url of the repository
 *
 * If `branch` is given, the url will be in the format of 'http://gitlab.com/user/repo/tree/branch'.
 * Otherwise, the url will be in the format of 'http://gitlab.com/user/repo'.
 */
export const getGitUrl = (url: string, branch: string): string => {
  if (!url) {
    return '';
  }
  const gitUrl = url.replace(/\.git$/, '');
  return branch ? `${gitUrl}/tree/${branch}` : gitUrl;
};
