//  Copyright (c) 2024 Huawei Technologies Co., Ltd.
//  openUBMC is licensed under Mulan PSL v2.
//  You can use this software according to the terms and conditions of the Mulan PSL v2.
//  You may obtain a copy of Mulan PSL v2 at:
//        #  http://license.coscl.org.cn/MulanPSL2
//  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
//  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
//  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
//  See the Mulan PSL v2 for more details.
function getPwdScore(len: number) {
  let pwdScore = 0;
  if (len >= 21) {
    pwdScore = len - 21 + (1.5 * 12) + (2 * 7) + 4;
  } else if (len >= 9 && len < 21) {
    pwdScore = ((len - 9 + 1) * 1.5) + (2 * 7) + 4;
  } else if (len >= 2 && len < 9) {
    pwdScore = ((len - 2 + 1) * 2) + 4;
  } else if (len >= 1 && len < 2) {
    pwdScore = 4;
  }
  return pwdScore;
}

function getValidatorParam(validator: any) {
  // 默认值设定
  let minCharLength = 0;
  let minCharTypeNumber = 0;
  let charTypeRegObject = {
    specialCharReg: /[~`!\?,.:;\-_'"\(\)\{\}\[\]\/<>@#\$%\^&\*\+\|\\=\s]/,
    lowerCharReg: /[a-z]+/,
    upperCharReg: /[A-Z]+/,
    digitsCharReg: /[0-9]+/,
  };

  // 长度
  const lengthParams = validator.find((item: any) => {
    return item.rangeSize || item.rangeSize === 0;
  });

  if (lengthParams) {
    // 通过rangeSize规则获取最小长度
    const rangeSize = lengthParams.rangeSize;
    if (rangeSize) {
      // 传至少1个值 [number]
      if (rangeSize && typeof rangeSize === 'object' && rangeSize instanceof Array && rangeSize.length >= 1) {
        minCharLength = rangeSize[0];
      } else if (rangeSize && typeof rangeSize === 'number') {
        // 只传一个值： number
        minCharLength = rangeSize;
      }
    }
  }

  // 最少要满足的字符类型个数
  const matchNumParams = validator.find((item: any) => {
    return item.minCharType || item.minCharType === 0;
  });

  if (matchNumParams) {
    // 通过minCharType规则获取最小字符类型及其正则
    const { minCharType } = matchNumParams;
    if (minCharType) {
      minCharTypeNumber = minCharType;
    }
  }

  // 返回对象值
  return {
    minCharLen: minCharLength,
    minCharTypeNum: minCharTypeNumber,
    charTypeRegObj: charTypeRegObject,
  };
}

/**
 * 计算密码等级
 * 低： 0~25.5（ 小于等于25 .5）
 * 中： 25.5~30(大于25 .5 小于等于30)
 * 高： 30~（大于30）
 * @param score 密码分数
 * @returns 密码等级
 */
function countLevel(
  score: number,
  minCharLen: number,
  minCharTypeNum: number,
  value: any,
  len: number,
  charTypeRegObj: any,
) {
  let level = 0;
  if (score > 30) {
    level = 2;
  } else if (score > 25.5 && score <= 30) {
    level = 1;
  } else if (score >= 0 && score <= 25.5) {
    level = 0;
  }
  level = levelHandle(minCharLen, minCharTypeNum, level, value, len, charTypeRegObj);
  return level;
}

// 密码降级处理
function levelHandle(psdLen: any, psdType: any, level: any, value: any, len: number, charTypeRegObj: any) {
  const type = getCharType(value, charTypeRegObj);
  let pwdLevel = level;
  if (level > 0) {
    if ((psdLen && len < psdLen) || (psdType && type < psdType)) {
      pwdLevel = level - 1;
    }
  }
  return pwdLevel;
}

// 获取当前密码字符种类
function getCharType(str: any, charTypeRegObj: any) {
  let typeNum = 0;
  for (const key in charTypeRegObj) {
    if (Object.prototype.hasOwnProperty.call(charTypeRegObj, key)) {
      const regExp = charTypeRegObj[key];
      if (regExp.test(str)) {
        typeNum++;
        regExp.lastIndex = 0;
      }
    }
  }
  return typeNum;
}

// 计算安全程度
// 初步看：之前v2的是根据字符长度和字符类型多少来进行评级的
export function pwdLevelFn(value: string, validator: any) {
  const validatorParam: any = getValidatorParam(validator);
  const { minCharLen, minCharTypeNum, charTypeRegObj } = validatorParam;
  // 根据字符个数初步计算熵值
  const len = value.length;
  let pwdScore = getPwdScore(len);

  // 同时存在大写字母和特殊字符，熵值+6
  if (
    charTypeRegObj?.upperCharReg?.test(value) &&
    charTypeRegObj?.specialCharReg?.test(value)
  ) {
    pwdScore += 6;
    // 重置正则表达式的lastIndex属性:只有正则表达式使用了表示全局检索的 "g" 标志时，该属性才会起作用，
    // 当前正则匹配到字串后，下次使用同样的正则匹配该字串时，正则检查位置会发生变化
    charTypeRegObj.upperCharReg.lastIndex = 0;
    charTypeRegObj.specialCharReg.lastIndex = 0;
  }

  // 根据熵值计算等级
  return countLevel(pwdScore, minCharLen, minCharTypeNum, value, len, charTypeRegObj);
}
