import { IColumn } from "../../store/table";
import { numberFormatter } from "../../utils/helper";
import { ISelect } from "./DataStatic";

export const Statistics = {
  // 计算合计sum | 计算个数num
  sum: (arr: any[], field?: string, type?: 'sum' | 'num', calculatedField?: string) => {
    if (arr.some(item => typeof item === 'number')) {
      const res = arr.reduce((total: number, curr: number) => +Number(+total) + Number(+curr), 0);
      return (res as number).toFixed(2)
    } else {
      let sum = 0;
      if (calculatedField && field) {
        let numerator = 0;//分子
        let denominator = 0;//分母
        arr.forEach(item => {
          numerator += (item[field] || 0) / 100 * (item[calculatedField] || 0);
          denominator += (item[calculatedField] || 0);
        })
        return denominator === 0 ? 0 : numerator / denominator * 100
      }
      arr.forEach(item => {
        // sum的时候当数值算， num的时候当1算 默认当数值算
        sum += Number(type === 'num' ? 1 : (item && field && item[field] ? item[field] : 0));
      });
      // 排序string型 会采用unicode排序 所以出参得是数字
      return Math.round((+sum || 0) * 100) / 100;
    }
  },
  max: (values: number[]): number => Math.max(...values),
  min: (values: number[]): number => Math.min(...values),
  colLen: (values: number[]): number => values?.length,
  avg: (values: number[]) => (Number(Statistics.sum(values)) / Statistics.colLen(values)).toFixed(2),
  std_v: (values: number[]): number => {
    let length = values?.length;
    let temp = new Array(length);
    const avg = Number(Statistics.avg(values));
    for (let i = 0; i < length; i++) {
      let dev = values[i] - avg;
      temp[i] = Math.pow(dev, 2);
    }
    let powSum = Number(Statistics.sum(temp));
    return Math.sqrt(powSum / length);
  },
  count_null: (values: number[]): number => values.filter(value => value === null).length,
  per: (arr: obj[], field: string, data: obj[], type?: 'sum' | 'num') => {
    let sumAll = 0;
    let sum = 0;
    arr.forEach(item => {
      // sum的时候当数值算， num的时候当1算 默认当数值算
      sum += Number(type === 'num' ? 1 : item?.[field] || 0);
    });
    data.forEach(item => {
      // sum的时候当数值算， num的时候当1算 默认当数值算
      sumAll += Number(type === 'num' ? 1 : item?.[field] || 0);
    });
    // 防止报错
    if (!+sumAll) return 0
    return sum / sumAll * 100;
  },
  g_per: (arr: obj[], field: string, data: obj[], groupList: string[]) => {
    const groupArr = groupList.slice(0, groupList.length - 1);
    const groupData = groupList.length < 3 ?
      data.filter(v => v[groupList[0]] === arr[0][groupList[0]]) :
      data.filter(v => groupArr.every(val => v[val] === arr[0][val]));
    let groupSum = 0;
    let sum = 0;
    sum += Number(Statistics.sum(arr, field));
    groupSum += Number(Statistics.sum(groupData, field));
    // 防止报错
    if (!+groupSum) return 0
    return sum / groupSum * 100;
  }
}
//计算分组
function groupBy(array: obj[], conditionFun: (rowData: obj) => any): obj[][] {
  let groups = {};
  array.forEach(function (o) {
    let group = JSON.stringify(conditionFun(o));
    groups[group] = groups[group] || [];
    groups[group].push(o);
  });
  return Object.keys(groups).map(function (group) {
    return groups[group];
  });
}
enum typeName {
  sum = 'sum',
  per = 'per',
  g_per = 'g_per',
  avg = 'avg',
  max = 'max',
  min = 'min',
  std_v = 'std_v',
  count_null = 'count_null'
}
//计算分组统计
export function computed(data: obj[], groudbyList: string[], statisByList: string[], typeList: string[], columns: any) {
  //计算分组数据
  let groudList = groupBy(data, (item) => {
    let str = '';
    groudbyList.forEach(groudStr => {
      str += item[groudStr]
    })
    return str;
  });
  //含有百分比计算方法的列先拿出来
  const percentList = columns.filter((col: any) => (col.isPercentage || col.pristine?.isPercentage)
    && (col.calculatedField || col.pristine?.calculatedField));
  return groudList.map(arr => {
    let firstRow = arr?.[0] || [];
    //行数据
    let rowData = {};
    //提取分组属性数据
    groudbyList.forEach(item => {
      rowData[item] = firstRow[item]
    })
    //提取计算数据属性
    statisByList.forEach(item => {
      const countType = groudbyList.includes(item) ? 'num' : 'sum';
      const targetCol = percentList.find((col: any) => col.name === item);
      typeList.forEach(type => {
        if (typeName[type] === 'per') {
          rowData[item + typeName[type]] = Statistics[type](arr, item, data, countType)
        } else if (typeName[type] === 'g_per') {
          rowData[item + typeName[type]] = Statistics[type](arr, item, data, groudbyList)
        } else if (typeName[type] === 'sum') {
          if (targetCol) {
            rowData[item + typeName[type]] = Statistics[type](arr, item, countType, targetCol.calculatedField ?? targetCol.pristine?.calculatedField)
          } else {
            rowData[item + typeName[type]] = Statistics[type](arr, item, countType)
          }
        } else {
          rowData[item + typeName[type]] = Statistics[type](arr.map(dataItem => dataItem?.[item]))
        }
      })
    })
    return rowData;
  })
}
//计算列统计
export function computedStatic(data: obj[], content: ISelect[], statisByList: string[], originColList: IColumn[]) {
  let tableData: any = [];
  //含有百分比计算方法的列先拿出来
  const percentList = originColList.filter((col: any) => (col.isPercentage || col.pristine?.isPercentage)
    && (col.calculatedField || col.pristine?.calculatedField));
  statisByList.forEach((info) => {
    let obj = {
      statistics: originColList.find(col => col.name === info)?.label || '',
    }
    const currCol: any = originColList.find(item => info === item.name);
    const targetCol: any = percentList.find((col: any) => col.name === info);
    const formatObj = {
      suffix: currCol.suffix ?? currCol.pristine?.suffix ?? '',
      prefix: currCol.prefix ?? currCol.pristine?.prefix ?? '',
      precision: currCol.precision ?? currCol.pristine?.precision,
      kilobitSeparator: currCol.kilobitSeparator ?? currCol.pristine?.kilobitSeparator
    }
    content.forEach((item) => {
      if (item.value === 'sum' && targetCol) {
        obj[item.value] = dealCellValue(Number(Statistics[item.value](data, info, 'sum', targetCol.calculatedField ?? targetCol.pristine?.calculatedField)), formatObj)
      } else {
        const values = data.map((dataItem) => dataItem[info])
        if (item.value == 'std_v') {
          obj[item.value] = Number(Statistics[item.value](values)).toFixed(2)
        } else if (item.value == 'count_null') {
          obj[item.value] = Statistics[item.value](values)
        } else {
          obj[item.value] = dealCellValue(Number(Statistics[item.value](values)), formatObj)
        }
      }
    })
    tableData.push(obj)
  })
  return tableData;
}

const dealCellValue = (originValue: number, formatObj: {
  suffix?: string,
  prefix?: string,
  kilobitSeparator?: boolean,
  precision?: number
}) => {
  const { suffix, prefix, precision, kilobitSeparator } = formatObj;
  let value: string | number = originValue;
  if (kilobitSeparator && originValue != null) {
    value = numberFormatter(originValue, precision)
  } else if (originValue != null && typeof originValue == 'number') {
    value = originValue.toFixed(precision)
  }
  if (value != null) {
    return typeof value == 'object' ? '[文件]' : `${prefix}${typeof value == 'string' ? value.replaceAll('\n', '').replaceAll('\r', '') : value}${suffix}`
  }
  return ''
}