/* eslint-disable no-param-reassign */
import {
  ConfigMaterialKey,
  GljType,
  IBaseGlj,
  ICalcOption,
  IComponent,
  IConfigMaterial,
  IDecimal,
  IInfoPriceItem,
  IProjectGlj,
  IProperty,
  ITenderSetting,
  TaxType,
} from '@sc/types';
import { roundForObj } from '@sc/util';
import { find } from 'lodash';

export const getInfoMarketPrice = (info: IInfoPriceItem, taxType: TaxType) => {
  // 1: 一般计税 2: 简易计税
  const fieldArray = ['noTaxPrice']; // 一般计税 - 不含税价 || 简易计税 - 含税价
  if (taxType === TaxType.GENERAL) {
    fieldArray.push('taxPrice');
  } else {
    fieldArray.unshift('taxPrice');
  }
  // 一个放后面，一个放前面
  let infoPrice = (info as any)[fieldArray[0]];
  if (infoPrice === null || infoPrice === undefined) infoPrice = (info as any)[fieldArray[1]]; // 信息价只有一个价格（含税价/不含税价），则不分计税方式，套用仅有的价格。
  return parseFloat(infoPrice);
};

// 计算采保费率后的市场价
export const calcMarketPriceByInfoPrice = (infoPrice: number, purchaseFeeRate: number, decimal: number) => {
  if (!purchaseFeeRate) return infoPrice;
  return roundForObj(infoPrice * (1 + purchaseFeeRate / 100), decimal);
};

// roundForObj()
// 返回五大项组成的索引
export const getIndex = (obj: IBaseGlj, props = ['code', 'name', 'specs', 'unit', 'type']): string => {
  let index = '';
  //! 优化：字符串拼接比数组push、join操作快很多，大项目下影响较大，所以使用字符串拼接
  for (let i = 0; i < props.length; i += 1) {
    const p = props[i];
    const tmpK = obj[p] === undefined || obj[p] === null || obj[p] === '' ? 'null' : obj[p];
    const str = i === props.length - 1 ? tmpK : `${tmpK}|-|`;
    index += str;
  }
  return index;
};

// 是否是人工
export const isLabour = (type: GljType) => {
  return type === GljType.LABOUR;
};

// 是否是材料
export const isMaterial = (type: GljType) => {
  const rootType = +String(type).charAt(0);
  return rootType === 2;
};

// 是否是机械
export const isMachine = (type: GljType) => {
  const rootType = +String(type).charAt(0);
  return rootType === 3;
};

/**
 * 判断工料机类型是否有组成物
 *
 * @param projectGlj 可以不传这个，默认会按glj去取
 *
 */
export const hasComponent = (projectGlj?: IProjectGlj) => {
  // 有组成物的类型
  const typeMap: { [key: number]: boolean } = {
    202: true,
    203: true,
    204: true,
    301: true,
    304: true,
    4: true,
  };
  if (projectGlj) {
    return typeMap[projectGlj.type] === true && projectGlj.components && projectGlj.components.length > 0;
  }
  return false;
};

const getProjectGlj = (glj: IBaseGlj, projectGljMap: Record<string, IBaseGlj>, index?: string) => {
  index = index || getIndex(glj);
  const projectGlj = projectGljMap[index] as IProjectGlj;
  if (projectGlj) return projectGlj;
  return undefined;
};

/**
 *
 * @param fieldID 如"glj.unitPrice"
 *
 */
export const getDecimal = (fieldID: string, decimal?: any) => {
  if (decimal) {
    if (fieldID.indexOf('.') !== -1) {
      const keyArray = fieldID.split('.');
      return decimal[keyArray[0]][keyArray[1]];
    }
    return decimal[fieldID];
  }

  return 0;
};

export const getMarketPrice = (
  projectGlj: IProjectGlj,
  tenderCoe = 1,
  projectGljMap: Record<string, IBaseGlj>,
  decimalObj: IDecimal
) => {
  if (hasComponent(projectGlj)) {
    let parentPrice = 0;
    for (const c of projectGlj.components as IComponent[]) {
      const cProjectGlj = getProjectGlj(c, projectGljMap);
      if (cProjectGlj) {
        let cMarketPrice = getMarketPrice(cProjectGlj, 1, projectGljMap, decimalObj);
        if (tenderCoe !== 1) cMarketPrice = roundForObj(cMarketPrice * tenderCoe, decimalObj.glj.unitPrice);
        const quantity = roundForObj(c.consumption, decimalObj.glj.quantity);
        const sumPrice = roundForObj(cMarketPrice * quantity, decimalObj.process);
        parentPrice = roundForObj(parentPrice + sumPrice, decimalObj.process);
      }
    }
    return roundForObj(parentPrice, decimalObj.glj.unitPriceHasMix);
  }
  const marketPrice = roundForObj(projectGlj.marketPrice, decimalObj.glj.unitPrice);
  // 调价的时候还要乘以调价系数
  if (tenderCoe !== 1) return roundForObj(marketPrice * tenderCoe, decimalObj.glj.unitPrice);
  return marketPrice;
};

// 取工料机基价(定额价)
export const getBasePrice = (projectGlj: IProjectGlj, decimalObj: IDecimal) => {
  let decimalKey = 'glj.unitPrice';
  if (hasComponent(projectGlj)) decimalKey = 'glj.unitPriceHasMix';
  const decimal = getDecimal(decimalKey, decimalObj);
  return roundForObj(projectGlj.basePrice, decimal);
};

export const getTenderPriceCoe = (projectGlj: IProjectGlj, tenderSetting?: ITenderSetting) => {
  let coe = 1;

  if (projectGlj.noAdjustPrice === false && tenderSetting) {
    coe = tenderSetting.gljPriceTenderCoe ? tenderSetting.gljPriceTenderCoe : 1;
  }

  return coe;
};

// 判断是否暂估
export const isEvaluate = (projectGljID: string, configMaterials: IConfigMaterial) => {
  const materials = configMaterials[ConfigMaterialKey.EVALUATE];

  return !!find(materials, { isRelated: true, projectGljID });
};

// 判断是否计算价差
export const calcPriceDiff = (projectGlj: IProjectGlj, configMaterials: IConfigMaterial, calcOption?: ICalcOption) => {
  if (calcOption) {
    const { calcEst, calcMain, calcAdd } = calcOption;
    if (isEvaluate(projectGlj.ID, configMaterials)) return calcEst; // 先按是否暂估判断
    // 再判断是否是主材和设备
    if (projectGlj.type === GljType.MAIN_MATERIAL || projectGlj.type === GljType.EQUIPMENT) return calcMain;
    // 再判断是否新增
    if (projectGlj.isAdd) return calcAdd;
  }
  return true;
};

// 取工料机的价格在确定subject数据已经获取全的情况下使用
export const getPrice = (
  glj: IBaseGlj,
  projectGljMap: Record<string, IBaseGlj>,
  unitProperty: { tenderSetting?: ITenderSetting },
  constructionProperty: { decimal: IDecimal; calcOption?: ICalcOption },
  configMaterial: IConfigMaterial,
  tender?: boolean
) => {
  let marketPrice = 0;
  let basePrice = 0;
  let tenderPrice = 0; // 调后价
  let adjustPrice = 0; // 调整价
  const projectGlj = getProjectGlj(glj, projectGljMap);
  if (projectGlj) {
    marketPrice = getMarketPrice(projectGlj, 1, projectGljMap, constructionProperty.decimal);
    tenderPrice = marketPrice;

    if (tender === true) {
      const tenderCoe = getTenderPriceCoe(projectGlj, unitProperty.tenderSetting);
      tenderPrice = getMarketPrice(projectGlj, tenderCoe, projectGljMap, constructionProperty.decimal);
    }

    if (calcPriceDiff(projectGlj, configMaterial, constructionProperty.calcOption)) {
      // 计取价差
      basePrice = getBasePrice(projectGlj, constructionProperty.decimal);
    } else {
      // 不计价差时 基价也为市场价
      basePrice = marketPrice;
    }
    adjustPrice = basePrice;
  }
  return { marketPrice, basePrice, tenderPrice, adjustPrice, projectGlj };
};
