import DefAPIConfigs from '../config/api-type/index';
import base from '../utils/base';

const toLowerCase = function (val, def) {
  try {
    return val.toLowerCase();
  } catch (err) {
    return def;
  }
};

export const CHECK_LEVEL = {
  WARN: 0,
  ERROR: 1
}

const DefReturn = { pass: true, msg: '', level: CHECK_LEVEL.WARN };

export class Checker {
  constructor(APIConfigs) {
    this.CHECK_LEVEL = CHECK_LEVEL;
    this.APIConfigs = APIConfigs || {};

    this._checker = {
      'any': { checker: val => true },
      'function': { checker: base.isFun },
      'string': { checker: base.isString },
      'boolean': { checker: base.isBoolean },
      'number': { checker: base.isNumber },
      'array': { checker: base.isArray },
    };
    this._getAPIChecker = null
  }

  /**
   * 注册顶级的校验方法
   */
  registAPIChecker(fun) {
    if (base.isFun(fun)) {
      this._getAPIChecker = fun
    }
  }

  /**
   * 注入校验的参数配置
   * @param {*} configs 
   */
  injectAPIConfigs(configs) {
    Object.assign(this.APIConfigs, configs || {});
  }

  /**
   * 注册自定义校验方法
   * @param {*} type 
   * @param {*} checker 
   * @param {*} errMsg 
   */
  register(type, checker, errMsg) {
    if (type && typeof checker === 'function') {
      this._checker[type] = { errMsg, checker };
    }
  }

  /**
   * 获取校验方法
   * @param {*} type 
   * @returns 
   */
  getChecker(type) {
    const tp = toLowerCase(type, null);
    const checker = this._checker[tp];
    if (checker) {
      return checker;
    }

    return null;
  }

  /**
   * 单个参数校验
   * @param {any} param 
   * @param {Object} 检验参照信息
   */
  check(config, param, path) {
    const { valueType: type, optional = true, forceCheck } = config || {};
    const level = forceCheck ? CHECK_LEVEL.ERROR : CHECK_LEVEL.WARN;

    if (!type) {
      return DefReturn
    }

    // 为空判断是否必填
    if (base.isEmpty(param)) {
      return {
        pass: optional,
        msg: !optional ? `${path} param is required` : '',
        level,
      }
    }

    // 未知类型
    const { checker, errMsg } = this.getChecker(type) || {};

    if (!checker) {
      return DefReturn
    }

    // 正常校验
    const pass = checker(param);
    const msg = errMsg ? `${path}: ${errMsg}` : `${path} type is not ${type}`;

    return {
      pass,
      msg: !pass ? msg : '',
      level
    }
  }

  /**
   * 参数校验
   * @param {Object} checkInfos { 'key': { type: 'number', errMsg: '报错信息' }}
   * @param {any} params { 'key': 1 }
   */
  checkAll(checkInfos, params, parentPath) {
    if (!base.isArray(checkInfos)) {
      return DefReturn
    }

    for (let i = 0; i < checkInfos.length; i++) {
      const checkInfo = checkInfos[i] || {};
      const key = checkInfo.name;

      let res = {};
      if (key) {
        res = this.check(checkInfo, params[key], `${parentPath}.${key}`);
      } else {
        res = this.checkAll(checkInfo, params[i], `${parentPath}[${i}]`);
      }

      if (!res.pass) {
        return res;
      }
    }

    return DefReturn
  }

  /**
   * 获取验证器
   * @param {*} moduleName 
   * @param {*} api 
   * @returns 
   */
  getAPIChecker(moduleName, api) {
    if (this._getAPIChecker) {
      const apiChecker = this._getAPIChecker(moduleName, api)
      if (base.isFun(apiChecker)) {
        return apiChecker;
      }
    }
    const mconfig = this.APIConfigs[moduleName] || {};
    const config = mconfig[api] || {};
    return (...params) => this.checkAll(config.args, params, 'args');
  }
}

export default new Checker(DefAPIConfigs);