import { roundForObj } from '@sc/util';
import evaluate from 'evaluator.js';

// 关键字组
export interface IKeywordItem {
  optionCode: string; // 选项号
  coe: string; // 系数 *1.29
  keyword: string;
  unit: string;
}

export interface IInfoPriceMain {
  classCode: string; // 别名编码 0749B01D01
  expString: string; // 表达式 ：X*(1+(A-1)+(B-1)+(C-1))
  basePrice: string; // 基价
}

/* eslint-disable import/prefer-default-export */
const replaceAll = (FindText: RegExp | string, RepText: string, str: string): string => {
  const regExp = new RegExp(FindText, 'g');
  return str.replace(regExp, RepText);
};

/**
 * 计算材料价
 * infoPrice：主表的数据
 * keywordItems ： 关键字列表
 */
export const calcMaterialExp = (infoPrice: IInfoPriceMain, keywordItems: IKeywordItem[]) => {
  const preCodeLength = 5; // 别名编码位数，可能要改成5位或6位
  const decimal = 2; // 小数位数
  const groupStr = infoPrice.classCode.substr(preCodeLength);
  let { expString } = infoPrice; // 计算式
  const matchKeywords: IKeywordItem[] = [];
  try {
    if (groupStr.length > 0) {
      let startIndex = 0;
      while (groupStr.length > startIndex) {
        const option = groupStr.substr(startIndex, 3); // 获取A01这样的编号
        const group = keywordItems.find(item => item.optionCode === option);
        if (group) {
          // 运距=15km  这种类型的要特殊处理 暂时没有办法处理~ 没法从编号中获取具体要加减多少
          const operator = group.coe.charAt(0); // 加 减 乘的操作
          const coeNumber = parseFloat(group.coe.substr(1)); // 要代入计算的系数
          let replaceStr = '';
          if (operator === '*') {
            // 乘法时，自减1
            replaceStr = `${coeNumber - 1}`;
          } else {
            // + 或者 - 操作符时，使用 (+10) 或者 （-10）来替换，
            replaceStr = `(${group.coe})`;
          }
          expString = replaceAll(option.charAt(0), replaceStr, expString);
          matchKeywords.push(group);
        }
        startIndex += 3;
      }
      // 替换基价
      expString = replaceAll('X', infoPrice.basePrice, expString);

      // 没找到的按0处理
      expString = replaceAll(/[a-zA-Z]/, '0', expString);
      return { price: roundForObj(evaluate(expString), decimal), matchKeywords };
    }
  } catch (error) {
    throw new Error('计算失败，表达式有误');
  }

  return { price: roundForObj(infoPrice.basePrice, decimal), matchKeywords };
};
