/**
 * 统计组件
 */
import { Button, message, Modal, Spin } from "antd";
import { isNil, orderBy } from "lodash";
import React, { useEffect, useRef, useState } from "react";
import { IColumn } from "../../store/table";
import { Action } from "../../types";
import { isMobile, uuid } from "../../utils/helper";
import { tools } from "../../utils/shell/tools";
import { DataArea, SelectContent, SelectWrapperGroup } from "./commonSelect";
import { Button as AmisButton } from '../../components';
import { Icon } from '../../components/icons';
import './dataStatic.scss';
import { computed } from "./staticTools";
import Dialog from "../../components/DragModal";
interface IProps {
  action?: Action;
  columns: IColumn[];
  data: {
    items: any[];//当前页数据
    selectedItems: any[];//选中数据
    itemRaws: any[]//前端分页时全部数据
  },
  loadDataOnce?: boolean;
  getAllData: () => Promise<any>;
  container: HTMLDivElement | null;
  crudTitle: string;
  originHeaderToolbar: any[];
  name: string;
  isStatic?: boolean;
  handleDealData: (toolType: string, label: string, schema: any) => void;
}
export interface CalcField {
  value: string;
  title: string;
  disabled?: boolean;
  icon?: string;
}
export type DataAreaType = 'some' | 'all' | 'present'
export interface OkParam {
  dataArea: DataAreaType;
  selectedGroupingFiledData: string[];
  selectedStatisticalFieldData: string[];
  selectedContent: string[];
}
export interface ISelect {
  title: string,
  value: string,
  disabled?: boolean,
  icon?: string
}
export const staticList: ISelect[] = [
  {
    title: '合计值',
    value: 'sum',
    icon: '#icon-toolsum'
  },
  {
    title: '平均值',
    value: 'avg',
    icon: '#icon-toolAvg'
  },
  {
    title: '最大值',
    value: 'max',
    icon: '#icon-toolmax'
  },
  {
    title: '最小值',
    value: 'min',
    icon: '#icon-toolmin'
  },
  {
    title: '标准差',
    value: 'std_v',
    icon: '#icon-toolstandardDeviation'
  },
  {
    title: '空值数',
    value: 'count_null',
    icon: '#icon-toolnull'
  },
  {
    title: '百分比',
    value: 'per',
    icon: '#icon-toolpercent'
  },
  {
    title: '组内百分比',
    value: 'g_per',
    icon: '#icon-toolgroupPercent1'
  },
];
export type StataticType = "sum" | "avg" | "max" | "min" | "std_v" | "count_null" | "per" | "g_per";
//统计字段类型，数字(11)，货币，百分比(18), 进度条(16)
const dataTypeArr = ['number', 'static-number', 'input-number', 'progress', 'static-progress'];
//分组字段类型支持所有类型，除了15，17，20，21，22，34，35，38，39
const ungroupDataTypeArr = ['html', 'static-html', 'input-rich-text', 'lion-upload', 'link', 'input-table-field', 'input-table-dynamic'];
const DataStatic = (props: IProps) => {
  const { action, columns, data: { items, selectedItems, itemRaws }, loadDataOnce, crudTitle,
    originHeaderToolbar, name, isStatic, handleDealData } = props;
  const [visible, setVisible] = useState(false);
  const [loading, setLoading] = useState(false);
  const [groupFields, setGroupFields] = useState<Array<CalcField>>([]);//分组字段列表
  const [groupSelect, setGroupSelect] = useState<Array<string>>([]);//分组字段选中数据
  const [staticFields, setStaticFields] = useState<Array<CalcField>>([]);//统计字段列表
  const [staticSelect, setStaticSelect] = useState<Array<string>>([]);//统计字段选中数据
  const [staticContent, setStaticContent] = useState<Array<string>>(['sum']);//统计内容选中数据
  const [dataArea, setDataArea] = useState<DataAreaType>('present');//数据范围
  //统计内容的置灰情况
  const [btnStatus, setBtnStatus] = useState<{ [key in StataticType]?: boolean }>({ "g_per": true, "per": true });
  const workRef = useRef<Worker>()
  useEffect(() => {
    workRef.current = new Worker('./public/worker/dataStatics.js')
    return () => {
      workRef.current?.terminate()
    }
  }, [])
  useEffect(() => {
    mountHandle();
  }, [columns])
  // useEffect(() => {
  //   if (!visible) {
  //     handleClose()
  //   } else {
  //     handleDefaultValue()
  //   }
  // }, [visible])
  const createSchema = (tableColList: any[], tableData: any[]) => {
    return ({
      type: "crud",
      data: {
        total: tableData.length,
        items: tableData
      },
      aliasTitle: crudTitle ? crudTitle + '-统计' : '统计',
      loadDataOnce: true,
      "name": uuid(),
      "affixHeader": true,
      "columns": tableColList,
      "filterTogglable": false,
      source: "${items}",
      "autoFillHeight": true,
      "multiple": true,
      "setBorder": true,
      "keepItemSelectionOnPageChange": false,
      "syncLocation": false,
      "headerToolbar": isMobile() ?
        [] : [
          {
            "redDot": false,
            "actionType": "export",
            "type": "action",
            "name": "default_export",
            "label": "导出",
            "icon": "#icon-tooltool_download",
            "tooltip": "默认导出",
            "align": "right",
            "close": true,
            "tooltipPlacement": "top"
          },
          ...(groupSelect.length ? originHeaderToolbar.filter(item =>
            ['tool-bar-action', 'data-statics', 'data-cross', 'data-chart', 'data-analysis'].includes(item.type))
            : [])
        ],
      "checkOnItemClick": false,
      "showIndex": false,
      "header": [],
      "footer": [],
      footerToolbar: [
        {
          "type": "pagination",
          "align": "right"
        },
        {
          "type": "switch-per-page",
          "align": "right"
        },
        {
          "type": "statistics",
          "align": "right"
        }
      ],
      isStatic: true,
      perPage: 100,
      perPageAvailable: [100, 200, 500, 1000]
    })
  }
  const handleDefaultValue = () => {
    const defaultValueStr = localStorage.getItem('static-' + name)
    if (!isNil(defaultValueStr)) {
      const defaultValues = JSON.parse(defaultValueStr)
      setGroupSelect(defaultValues.groupSelect)
      setStaticSelect(defaultValues.staticSelect)
      setStaticContent(defaultValues.staticContent)
      setDataArea(defaultValues.dataArea)
      handleContent(defaultValues.groupSelect?.length > 0)
    } else {
      let list: string[] = [];
      columns.forEach((item: any) => {
        if (item.pristine.isNumerical || item?.isNumerical) list.push(item.name)
      })
      setStaticSelect(list)
    }
  }
  //根据column 数据进行分组 和 统计列分类
  const mountHandle = () => {
    const groupFileds: CalcField[] = [];
    const statisticsFields: CalcField[] = [];
    columns.forEach((col: any) => {
      const { type, label, name } = col;
      let obj: any = Object.assign({}, col, {
        title: label,
        value: name
      })
      if (dataTypeArr.includes(type)) {
        statisticsFields.push(obj)
      }
      if (!ungroupDataTypeArr.includes(type)) {
        groupFileds.push(obj)
      }
    });
    setGroupFields(groupFileds)
    setStaticFields(statisticsFields)
  }
  const handleClose = () => {
    setGroupSelect([])
    setStaticSelect([])
    setStaticContent(['sum'])
    setDataArea('present')
    setBtnStatus({
      "sum": false,
      "g_per": true,
      "per": true,
      "avg": false,
      "max": false,
      "min": false,
      "std_v": false,
      "count_null": false
    })
  }
  const handleAction = () => {
    setVisible(true)
  }
  const renderButton = () => {
    return <AmisButton onClick={handleAction}>
      <Icon icon={action?.icon ?? "#icon-tooltool_autowidth"} className="icon" symbol />
      {action?.label}
    </AmisButton>
  }
  const handleGroupSelectsChange = (value: string[]) => {
    setGroupSelect(value)
    setStaticContent(['sum'])
    handleContent(value?.length > 0);
    setStaticFields(staticFields.map(item => ({ ...item, disabled: value.includes(item.value) })));
  }
  const handleStaticSelectsChange = (value: string[]) => {
    setStaticSelect(value);
    setGroupFields(groupFields.map(item => ({ ...item, disabled: value.includes(item.value) })));
  }
  // 统计内容字段变化联动置灰情况
  const handleStaticTypeChange = (value: string[]) => {
    setStaticContent(value)
    handleContent(groupSelect?.length > 0);
  }
  // 置灰情况变化规则
  const handleContent = (hasGroupFields: boolean) => {
    setBtnStatus({
      "sum": false,
      "g_per": !hasGroupFields,
      "per": !hasGroupFields,
      "avg": false,
      "max": false,
      "min": false,
      "std_v": hasGroupFields,
      "count_null": hasGroupFields
    })
  }
  //统计校验
  const check = (param: OkParam) => {
    const { selectedContent, selectedGroupingFiledData, selectedStatisticalFieldData } = param;
    if (tools.isEmpty(selectedGroupingFiledData) && tools.isEmpty(selectedStatisticalFieldData)) {
      return message.warn({
        content: '分组字段和统计字段至少选择一项'
      })
    }
    if (tools.isEmpty(param.dataArea)) {
      return message.warn({
        content: '请选择范围'
      });
    }
    if (tools.isEmpty(selectedContent)) {
      return message.warn({
        content: '内容不能为空'
      });
    }
    if (
      selectedGroupingFiledData.length
      && selectedGroupingFiledData.find((item) => selectedStatisticalFieldData.includes(item))
    ) {
      return message.warn({
        content: '分组字段不能和统计字段相同'
      });
    }
    return true;
  }
  //开启新线程计算数据
  const buildWorkerData = ({
    calcData, groupSelect, staticSelect, staticContent, selectedContentItem, columns
  }: {
    calcData: any[], groupSelect: string[], staticSelect: string[],
    staticContent: string[], selectedContentItem: ISelect[], columns: any[]
  }) => {
    return new Promise<any[]>((resolve, reject) => {
      if (workRef.current) {
        workRef.current.postMessage({
          calcData, groupSelect, staticSelect,
          staticContent, selectedContentItem, columns
        })
        workRef.current.onmessage = (e: MessageEvent) => {
          resolve(e.data)
        }
        workRef.current.onmessageerror = (e) => {
          reject(e.data)
        }
      } else {
        reject('webwork error')
      }
    })
  }
  const handleOk = async () => {
    const param = { selectedContent: staticContent, dataArea, selectedGroupingFiledData: groupSelect, selectedStatisticalFieldData: staticSelect }
    if (check(param) !== true) {
      return false;
    }
    if (dataArea === 'all' && !loadDataOnce) {
      setLoading(true)
      const res = await props.getAllData();
      if (res == null) { return }
      if (!res.total) {
        message.info({ content: "统计结果为空" });
        setLoading(false)
        return;
      }
      const selectedContentItem = staticList.filter((item) => staticContent.includes(item.value));
      const colList = getStaticPartColumns(param, columns, selectedContentItem);
      buildWorkerData({
        calcData: res.items, groupSelect, staticSelect,
        staticContent, columns, selectedContentItem
      }).then(resData => {
        const newTableData = orderBy(resData, colList.map(item => item.name));
        setLoading(false)
        handleDealData('data-static', crudTitle ? crudTitle + '-统计' : '统计', createSchema(colList, newTableData))
        setVisible(false)
      })
    } else {
      if (dataArea === 'some' && !selectedItems?.length) {
        return message.warn({
          content: '选中数据为空'
        });
      }
      if (dataArea === 'present' && !items?.length) {
        return message.warn({
          content: '当前页数据为空'
        });
      }
      if (dataArea === 'all' && !itemRaws?.length) {
        return message.warn({
          content: '当前数据为空'
        });
      }
      setLoading(true)
      const selectedContentItem = staticList.filter((item) => staticContent.includes(item.value));
      const colList = getStaticPartColumns(param, columns, selectedContentItem);
      const calcData = dataArea === 'some' ? selectedItems : dataArea === 'present' ? items : itemRaws
      buildWorkerData({
        calcData, groupSelect, staticSelect, staticContent, columns, selectedContentItem
      }).then(resData => {
        // const resData = computed(calcData, groupSelect, staticSelect, staticContent, columns);
        const newTableData = orderBy(resData, colList.map(item => item.name));
        setLoading(false)
        handleDealData('data-static', crudTitle ? crudTitle + '-统计' : '统计', createSchema(colList, newTableData))
        setVisible(false)
      })
    }
  }

  //计算部分数据统计列
  const getStaticPartColumns = (param: OkParam, originColList: IColumn[], selectedContentItem: ISelect[]) => {
    const { selectedStatisticalFieldData, selectedGroupingFiledData } = param;
    let tableColsName = [...selectedGroupingFiledData, ...selectedStatisticalFieldData];
    let colList: any[] = []
    //没有选择分组字段
    if (!selectedGroupingFiledData || selectedGroupingFiledData.length === 0) {
      selectedContentItem.forEach(content => {
        colList.push({
          name: content.value,
          label: content.title,
          sortable: false,
          isNumerical: false
        })
      })
      let col = {
        name: 'statistics',
        label: '统计',
        sortable: true
      }
      colList.unshift(col);
    } else {
      colList = originColList.filter(col => {
        return col.name && tableColsName.includes(col.name)
      }).map(item => ['number', 'input-number'].includes(item.type) ? { ...item, ...item.pristine } : item);
      colList.filter(col => (selectedStatisticalFieldData.length ? selectedStatisticalFieldData : selectedGroupingFiledData)
        .includes(col.name)).forEach(item => {
          selectedContentItem.forEach(info => {
            const name = item.name + info.value;
            const calcField = item.calculatedField ?? item.pristine?.calculatedField;
            colList.push({
              name: name,
              type: 'number',
              label: item.label + info.title,
              suffix: info.value === 'per' || info.value === 'g_per' ? '%' : (item.suffix ?? item.pristine?.suffix),
              prefix: info.value === 'per' || info.value === 'g_per' ? '' : (item.prefix ?? item.pristine?.prefix),
              kilobitSeparator: info.value === 'per' || info.value === 'g_per' ? false : (item.kilobitSeparator ?? item.pristine?.kilobitSeparator),
              precision: ['per', 'g_per', 'std_v', 'avg'].includes(info.value) ? 2 : (item.precision ?? item.pristine?.precision),
              isNumerical: true,
              align: item.align ?? item.pristine?.align,
              showUppercase: item.showUppercase ?? item.pristine?.showUppercase,
              sortable: true,
              isPercentage: item.isPercentage ?? item.pristine?.isPercentage,
              calculatedField: calcField ? (
                info.value === 'sum' ? calcField + 'sum' : calcField
              ) : undefined,
              groupName: item.groupName ?? item.pristine?.groupName,
              groupLabels: item.groupLabels ?? item.pristine?.groupLabels
            })
          })
        })
      //将统计字段剔除
      colList = colList.filter((item) => !selectedStatisticalFieldData.includes(item.name));
    }
    return colList;
  }
  const setDefault = () => {
    const param = { staticContent, dataArea, groupSelect, staticSelect }
    localStorage.setItem('static-' + name, JSON.stringify(param))
    message.success('设置成功！')
  }
  const onReset = () => {
    if (localStorage.getItem('static-' + name)) {
      handleDefaultValue()
    } else {
      let list: string[] = [];
      columns.forEach((item: any) => {
        if (item.pristine.isNumerical || item?.isNumerical) list.push(item.name)
      })
      setGroupSelect([])
      setStaticSelect(list)
      setStaticContent(['sum'])
      setDataArea('present')
    }
  }
  const renderFooter = () => {
    return <div className="statics-footer">
      <div>
        {!isStatic && <Button loading={loading} className="tools-set-default" onClick={setDefault}>设置默认值</Button>}
        <Button loading={loading} className="tools-reset-default" onClick={onReset}>重置</Button>
      </div>
      <div>
        <Button loading={loading} onClick={() => setVisible(false)}>取消</Button>
        <Button loading={loading} type="primary" onClick={handleOk}>确认</Button>
      </div>
    </div>
  }
  const renderBody = () => {
    return <div>
      <div className="select-wrapper-group-container">
        <SelectWrapperGroup
          label="分组字段"
          data={groupFields}
          onChange={handleGroupSelectsChange}
          defaultValue={groupSelect}
        />
        <SelectWrapperGroup
          label="统计字段"
          data={staticFields}
          defaultValue={staticSelect}
          onChange={handleStaticSelectsChange}
        />
      </div>
      <SelectContent
        label="统计内容"
        data={staticList?.map(item => Object.assign({}, item, { disabled: btnStatus[item.value] || false }))}
        defaultValue={staticContent}
        onChange={handleStaticTypeChange}
      />
      <DataArea
        value={dataArea}
        className="static-data-area"
        onChange={(e) => {
          setDataArea(e.target.value)
        }}
      />
    </div>
  }
  return (
    <>
      {renderButton()}
      {!isMobile() && visible && <Dialog getContainer={props.container || document.body}
        zIndex={1000} dialogVisible={visible} title={'统计'} width={540} destroyOnClose centered
        className={'statics-modal'} drag
        afterClose={handleClose}
        footer={renderFooter()}
        onCancel={() => setVisible(false)}
      >
        <Spin spinning={loading}>
          {renderBody()}
        </Spin>
      </Dialog>
      }
    </>
  )
}
export default DataStatic;