import React, { useState, useCallback, useRef, useEffect, useContext } from 'react';
import { Input, Form, Typography, Button, Select, Row, Col, Popover, Checkbox, Tooltip, Table, Pagination, Space } from 'antd';
import { CheckOutlined, PlusOutlined, QuestionCircleOutlined, DeleteOutlined } from '@ant-design/icons';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import update from 'immutability-helper';
import { useClickAway } from 'ahooks';
import { useContextMenu, Menu as RcMenu, Item as RcItem } from "react-contexify";
import ResizeObserver from 'rc-resize-observer';
import { Resizable } from 'react-resizable';

import { generateUUID, highlightSearchContentByTerms, showMessage, inputWidth, paginate } from '../../../../util';
import { dispatch, dispatchLatest } from '../../../../model'; 
import { addEventListenerForSidebar, removeEventListenerForSidebar } from './Help';
import { AppContext } from '../../../../App';
import DebounceInput from './DebounceInput';
import SuggestTable from './SuggestTable';
import { AttentionSvg, UnAttentionSvg } from './ModelSvg';
import { EditModelContext } from './ContextManage';

import './ImportActionTable.less';

const { Option } = Select;

const type = `DragableTableBodyRow${generateUUID()}`;
const perSuggestCount = 5;
const supportMaxAttributeCountPerPage = 100;
const MENU_ID = 'model-attribute-menu';

const InputDebounce = DebounceInput(300)(Input);

const ResizeableHeaderCell = props => {
  const { onResize, width, onClick, ...restProps } = props;

  if (!width) {
    return <th {...restProps} />;
  }

  return (
    <Resizable
      width={width}
      height={0}
      handle={
        <span
          className="react-resizable-handle"
          onClick={(e) => {
            e.stopPropagation();
          }}
        />
      }
      onResize={onResize}
      draggableOpts={{ enableUserSelectHack: false }}
    >
      <th
        onClick={onClick}
        {...restProps}
      />
    </Resizable>
  );
};

export const DatatypeInput = ({ value = {}, datatypes, onChange }) => {

  const onNameChange = (value) => {

    let currentDatatype = {}; 
    (datatypes||[]).forEach((datatype, index) => {
      if (value === datatype.name) {
        currentDatatype = datatype;
      }
    })

    triggerChange({ 
      name: value,
      cnName: currentDatatype.cnName,
      parameterNames: currentDatatype.parameterNames,
      parameterCnNames: currentDatatype.parameterCnNames,
      parameterValues: currentDatatype.parameterValues
    });
  }

  const onParameterValuesChange = (e, index) => {

    const parameterValue = e.target.value;
    const reg = /^-?\d*(\.\d*)?$/;
    if ((!isNaN(parameterValue) && reg.test(parameterValue)) || parameterValue === '') {
      const newParameterValues = [...(value.parameterValues||[])];

      //默认为0
      newParameterValues[index] = parameterValue;
      triggerChange({ parameterValues: newParameterValues });
    }
  }

  const triggerChange = (changedValue) => {
    onChange && onChange({
      ...value,
      ...changedValue,
    });
  };

  //value有可能为空
  value = value ? value: {};

  return (
    <>
      <Row align='middle'>
        <Col span={9}>
          <span>名称:</span>
        </Col>
        <Col span={15}>
          <span onClick={e => e.stopPropagation()}>
            <Select 
              onChange={onNameChange} 
              value={value.name || ''} 
              placeholder='请选择类型名称'
            >
            {
              (datatypes||[]) && datatypes.map((_datatype, index) => {
                return (
                  <Option key={_datatype.name||''}>{_datatype.name||''}</Option>
                );
              })
            }
            </Select>
          </span>
        </Col>
      </Row> 
      {
        (value.parameterCnNames||[]).map((parameterCnName, index) => {
          //使用InputNumber:当value改变时 InputNumber显示值没改变 但实际值有改变 是ant design的bug 这里使用只能输入数字的Input
          return (
            <Row key={index} className='mt-2' align='middle'>
              <Col span={9}>
                <span>{`${parameterCnName||''}:`}</span>
              </Col>
              <Col span={15}>
                <Input        
                  onChange={(e) => {
                    onParameterValuesChange(e, index);
                  }}  
                  value={value.parameterValues[index] || ''} 
                  style={{ width: '100%' }}
                  placeholder='请输入一个整数'
                />
              </Col>
            </Row>
          );
        })
      }
    </>
  )
}

export const EditableCell = ({
  editing,
  dataIndex,
  colTitle,
  inputType,
  record,
  index,
  datatypes,
  require,
  children,
  ...restProps
}) => {

  let editingComponent = null;
  if (editing) {
    if (dataIndex !== 'datatype') {

      const inputNode = inputType === 'check' ? <Checkbox /> : <InputDebounce />

      editingComponent = (
        <Form.Item
          name={dataIndex}
          style={{
            margin: 0,
          }}
          valuePropName={(inputType==='check')? 'checked': 'value'}
          rules={[
            {
              required: (require===null)?false:require,
              message: `请输入${colTitle}!`,
            },
          ]}
        >
        { inputNode }
        </Form.Item>
      );
    } else {

      editingComponent = (
        <Form.Item
          name={dataIndex}
          style={{
            margin: 0,
          }}
          valuePropName={'value'}
          rules={[
            {
              required: (require===null)?false:require,
              message: `请输入${colTitle}!`,
            },
          ]}
        >
          <DatatypeInput datatypes={datatypes} />
        </Form.Item>
      )
    }
  }


  return (
    <td {...restProps}>
      {editing ? (
        editingComponent
      ) : (
        children
      )}
    </td>
  );
};

export const DragableBodyRow = ({ index, moveRow, className, style, ...restProps }) => {

  const ref = useRef();
  const [{ isOver, dropClassName }, drop] = useDrop(
    () => ({
      accept: type,
      collect: monitor => {

        const { index: dragIndex } = monitor.getItem() || {};
        if (dragIndex === index) {
          return {};
        }
        return {
          isOver: monitor.isOver(),
          dropClassName: dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
        };
      },
      drop: item => {
        if (moveRow) {
          moveRow(item.index, index);
        }
      },
    }),
    [index, moveRow],
  );
  const [, drag] = useDrag(
    () => ({
      type,
      item: () => {
        addEventListenerForSidebar("containerId");
        return { index }; 
      },
      end: (_, __) => {
        removeEventListenerForSidebar();
      }, 
      collect: monitor => ({
        isDragging: monitor.isDragging(),
      }),
    }),
    [index, moveRow],
  );
  drop(drag(ref));

  return (
    <tr
      ref={ref}
      className={`${className}${isOver ? dropClassName : ''}`}
      style={{ cursor: 'move', ...style }}
      {...restProps}
    />
  );
};

export const ImportActionTable = (props) => {
  const { modelerData, onChange, editable, supportedDatatypes, constraint, template, validateReports, type = 'model', terms, action, originAction } = props;
  const [ data, setData ] = useState([]);

  const [ form ] = Form.useForm();
  const [ editingKey, setEditingKey ] = useState('');
  const [ loadingSuggest, setLoadingSuggest ] = useState(false);
  const [ suggests, setSuggests ] = useState([]);
  const [ suggestHaveMore, setSuggestHaveMore ] = useState(false);
  const [ suggestOffset, setSuggestOffset ] = useState(1);
  const [ currentChangedValues, setCurrentChangedValues] = useState({});
  const [ englishSuggests, setEnglishSuggests ] = useState([]);
  const [ keywordCondition, setKeywordCondition ] = useState({ keyword: '', needFilter: true });
  const { keyword, needFilter } = keywordCondition;
  const [ tableWidth, setTableWidth ] = useState(0);

  const [ filterPageCondition, setFilterPageCondition ] = useState({ pageNum: 1, pageSize: supportMaxAttributeCountPerPage, filterData: [] });
  const [ filterPageData, setFilterPageData ] = useState([]);
  const { pageNum, pageSize, filterData } = filterPageCondition;
  const [ insertIndex, setInsertIndex ] = useState(0);
  const [ currentItem, setCurrentItem ] = useState(null);

  const { attrIsEditingFunction } = useContext(EditModelContext);

  const moveRowRef = useRef({ data, pageNum, pageSize });
  const tableRef = useRef(null);
  const termsRef = useRef(null);
  const autoTranslateRef = useRef(false);

  const { show } = useContextMenu({
    id: MENU_ID,
  });

  const cols = [
    {
      title: '序号',
      dataIndex: 'key',
      editable: false,
      width: 60,
      fixed: 'left',
      render: (text, record, index) => {
        return (index+1).toString();
      }
    },
    {
      title: '中文名称',
      width: 200,
      dataIndex: 'cnName',
      editable: true,
      ellipsis: true,
      require: true,
      fixed: 'left',
      render: (text, _, __) => {
        return (
          <Tooltip title={text||''}>
          <span>
          {highlightSearchContentByTerms(text, termsRef.current)}
          </span>
          </Tooltip>
        )
      }
    },
    {
      title: '英文名称',
      width: 200,
      dataIndex: 'name',
      editable: true,
      ellipsis: true,
      require: true,
      render: (text, record, index) => {
        return (
          <Tooltip title={text||''}>
          <span style={{ fontWeight: 'bold' }} >{highlightSearchContentByTerms(text, termsRef.current)}</span>
          </Tooltip>
        )
      }
    },
    {
      title: '类型',
      width: (editingKey!=='')?250:150,
      dataIndex: 'datatype',
      editable: true,
      ellipsis: true,
      require: true,
      render: (_, record, __) => {
        if (record?.datatype) {

          if ((record?.datatype?.name==='Char'||record?.datatype?.name==='Varchar') && record?.datatype?.parameterValues?.length>0) {

            return `${record?.datatype?.name||''}(${(record?.datatype?.parameterValues[0]?record.datatype.parameterValues[0]:0)})`;
          
          } else if ((record?.datatype?.name==='Decimal'||record?.datatype?.name==='Numeric') && record?.datatype?.parameterValues?.length>1) {
            return `${record?.datatype?.name||''}(${(record?.datatype?.parameterValues[0]?record.datatype.parameterValues[0]:0)},${(record?.datatype?.parameterValues[1]?record.datatype.parameterValues[1]:0)})`;
          }

          return record.datatype.name||'';
        }

        return '';
      }
    },
    {
      title: 'Not Null',
      width: 80,
      dataIndex: 'notNull',
      editable: (type==='model'?true:false),
      render: (notNull, record, index) => {
        if (!notNull) {
          return '-'; 
        } else if (notNull) {
          return (
            <CheckOutlined />
          )
        }

        return '';
      }
    },
    {
      title: '主键',
      width: 50,
      dataIndex: 'partOfPrimaryKeyLogically',
      editable: (type==='model'?true:false),
      render: (partOfPrimaryKeyLogically, record, index) => {
        if (!partOfPrimaryKeyLogically) {
          return '-'; 
        } else if (partOfPrimaryKeyLogically === true) {
          return (
            <CheckOutlined />
          )
        }

        return '';
      }
    },
    {
      title: '外键',
      width: 50,
      dataIndex: 'foreignKey',
      editable: (type==='model'?true:false),
      render: (foreignKey, record, index) => {
        if (!foreignKey) {
          return '-'; 
        } else if (foreignKey === true) {
          return (
            <CheckOutlined />
          )
        }

        return '';
      }
    },
    // {
    //   title: '重点关注',
    //   width: 75,
    //   dataIndex: 'needAttention',
    //   editable: (type==='model'?true:false),
    //   render: (needAttention, record, index) => {
    //     if (!needAttention) {
    //       return '-'; 
    //     } else if (needAttention === true) {
    //       return (
    //         <CheckOutlined />
    //       )
    //     }

    //     return '';
    //   }
    // },
    {
      title: '业务含义',
      dataIndex: 'remark',
      editable: true,
      ellipsis: true,
      require: true,
      width: 200,
      render: (text, _, __) => {
        return (
          <Tooltip title={text||''}>
            <span>
            {highlightSearchContentByTerms(text, termsRef.current)}
            </span>
          </Tooltip>
        )
      }
    },
    {
      title: '默认值',
      dataIndex: 'defaultValue',
      editable: true,
      ellipsis: true,
      width: 100,
      render: (text, _, __) => {
        return (
          <Tooltip title={text||''}>
            <span>
            {highlightSearchContentByTerms(text, termsRef.current)}
            </span>
          </Tooltip>
        )
      }
    },
    {
      title: '计算规则',
      dataIndex: 'definition',
      editable: true,
      ellipsis: true,
      width: 200,
      render: (text, _, __) => {
        return (
          <Tooltip title={text||''}>
            <span>
            {highlightSearchContentByTerms(text, termsRef.current)}
            </span>
          </Tooltip>
        )
      }
    },
    {
      title: '值域',
      dataIndex: 'valueRange',
      editable: true,
      ellipsis: true,
      width: 100,
      render: (text, _, __) => {
        return (
          <Tooltip title={text||''}>
            <span>
            {highlightSearchContentByTerms(text, termsRef.current)}
            </span>
          </Tooltip>
        )
      }
    },
  ];

  const [ columns, setColumns ] = useState(cols);

  useClickAway(() => {
    save();
  }, tableRef);

  useEffect(() => {
    attrIsEditingFunction && attrIsEditingFunction(editingKey!=='');
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [ editingKey ])

  //规则改变的时候 数据表为可编辑状态
  useEffect(() => {
    setEditingKey('');
  }, [constraint, template, modelerData])

  useEffect(() => {
    termsRef.current = terms;
    setData(modelerData?.easyDataModelerDataModelAttributes||[]);

    moveRowRef.current.data = (modelerData?.easyDataModelerDataModelAttributes||[]);

    let _filterData = (modelerData?.easyDataModelerDataModelAttributes||[]).filter(item => (item?.name||'').indexOf(keyword)!==-1 || (item.cnName).indexOf(keyword)!==-1);

    setFilterPageCondition({...filterPageCondition, filterData: _filterData});

    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [modelerData, terms])

  useEffect(() => {
    if (needFilter) {
      let _filterData = (modelerData.easyDataModelerDataModelAttributes||[]).filter(item => (item?.name||'').indexOf(keyword)!==-1 || (item.cnName).indexOf(keyword)!==-1);

      setFilterPageCondition({...filterPageCondition, ...{filterData: _filterData, pageNum: 1} });
    }
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [keywordCondition])

  useEffect(() => {
    moveRowRef.current.pageNum = pageNum;
    moveRowRef.current.pageSize = pageSize;

    if (filterData.length > supportMaxAttributeCountPerPage) {

      let _filterPageData = paginate(filterData, pageNum, pageSize);

      if ((_filterPageData||[]).length===0 && pageNum > 1) {
        setFilterPageCondition({...filterPageCondition, pageNum: (pageNum-1)});
        moveRowRef.current.pageNum = pageNum - 1;
      } else {
        setFilterPageData(_filterPageData);
      }
    } else {
      setFilterPageData(filterData);
    }
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [filterPageCondition])

  useEffect(() => {
    mergedColumns();
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [validateReports, editable, editingKey])

  const isEditing = (record) => record?.iid === editingKey;

  const onAddClick = (event) => {

    event.stopPropagation();  

    save().then(result => {
      if (result) {

        setKeywordCondition({ keyword: '', needFilter: false });

        const iid = generateUUID();
        const newData = [...moveRowRef.current.data, {iid}];
        
        if (newData.length > supportMaxAttributeCountPerPage) {
          
          const totalNum = parseInt(newData.length/supportMaxAttributeCountPerPage) + ((newData.length%supportMaxAttributeCountPerPage===0)?0:1);
          
          setFilterPageCondition({...filterPageCondition, ...{ filterData: newData, pageNum: totalNum }});
        } else {
          setFilterPageCondition({...filterPageCondition, ...{ filterData: newData}});
        }
    
        setInsertIndex(newData.length-1);
    
        edit(newData[newData.length-1], false);
        setTimeout(() => {
          document.getElementById(`field-${iid}`)?.scrollIntoView();
        }, 200)
      }
    })
  }

  const insertToFront = (record) => {
    save().then(result => {
      if (result) {
        setKeywordCondition({ keyword: '', needFilter: false });

        let newData = [...moveRowRef.current.data];
        const index = newData.findIndex((item) => record.iid === item.iid);

        const iid = generateUUID();

        if (index === 0) {
          newData = [{iid}, ...newData];
          setInsertIndex(0);
          edit(newData[0], false);
        } else {
          newData.splice(index, 0, {iid});
          setInsertIndex(index);
          edit(newData[index], false);
        }

        const _pageNum = parseInt((index+1)/supportMaxAttributeCountPerPage) + (((index+1)%supportMaxAttributeCountPerPage===0)?0:1);

        setFilterPageCondition({...filterPageCondition, ...{ filterData: newData, pageNum: _pageNum}});

        setTimeout(() => {
          document.getElementById(`field-${iid}`)?.scrollIntoView();
        }, 200)
      }
    })
  }

  const insertToBack = (record) => {
    save().then(result => {
      if (result) {
        setKeywordCondition({ keyword: '', needFilter: false });

        const newData = [...moveRowRef.current.data];
        const index = newData.findIndex((item) => record.iid === item.iid);

        const iid = generateUUID();
        newData.splice(index+1, 0, {iid});

        const _pageNum = parseInt((index+2)/supportMaxAttributeCountPerPage) + (((index+2)%supportMaxAttributeCountPerPage===0)?0:1);

        setFilterPageCondition({...filterPageCondition, ...{ filterData: newData, pageNum: _pageNum}});
        
        setInsertIndex(index+1);
        edit(newData[index+1], false);

        setTimeout(() => {
          document.getElementById(`field-${iid}`)?.scrollIntoView();
        }, 200)
      }
    })
  }

  const editLogic = (record) => {
    form.resetFields();
    form.setFieldsValue(record);

    setEditingKey(record?.iid);
    autoTranslateRef.current = ((record?.name||'')==='');

    if ((record?.cnName||'')!=='') {
      onValuesChange({ cnName: record?.cnName }, record, 1, record?.iid);
    } else if ((record?.name||'')!=='') {
      onValuesChange({ name: record?.name }, record, 1, record?.iid);
    }
  }

  const edit = (record, needSave = true) => {
    if (needSave) {
      save().then((result) => {
        if (result) {
          editLogic(record);
        }
      }); 
    } else {
      editLogic(record);
    }
  };

  const removeLogic = (record) => {
    const newData = [...moveRowRef.current.data];
    const index = newData.findIndex((item) => record.iid === item.iid);

    if (index !== -1) {
      newData.splice(index, 1);
    }

    onChange && onChange(newData);
  }

  const remove = (record) => {
    if (record.iid !== editingKey) {
      save().then(result => {
        if (result) {
          removeLogic(record);
        }
      })
    } else {
      removeLogic(record);
    }
  }

  const preSaveDataModel = (attribute) => {
    dispatch({
      type: 'datamodel.preSaveDataModel',
      payload: { 
        data: attribute
      },
      callback: remoteData => {
        const newData = [...moveRowRef.current.data];
        const index = (newData||[]).findIndex((item) => attribute.iid === item.iid);
    
        if (index !== -1) {
          newData.splice(index, 1, remoteData);
          moveRowRef.current.data = newData;
          onChange && onChange(newData, false);
        }
      },
    })
  }

  const save = async() => {

    try {

      if (editingKey!=='') {

        const row = await form.validateFields();

        if ((row.datatype.name||'')==='') {
          form.setFields([{ name: 'datatype', errors: ['必须选择类型'] }]);
          return;
        }

        (row.datatype.parameterNames||[]).forEach((parameterName, index) => {
          if (!row.datatype.parameterValues[index] || row.datatype.parameterValues[index]==='') {
            row.datatype.parameterValues[index] = 0;
          }
        })

        const newData = [...data];
    
        const index = newData.findIndex((item) => editingKey === item.iid);
    
        //判断字段名称是否唯一
        let _index;
        if (index === -1) {
          _index = (data||[]).findIndex(item => item.name === row.name);
        } else {
          const newDataExcludeSelf = [...data];
          newDataExcludeSelf.splice(index, 1);  
          _index = (newDataExcludeSelf||[]).findIndex(item => item.name === row.name);
        }

        if (_index !== -1) {
          form.setFields([{ name: 'name', errors: ['字段名称不能重复'] }]);
          return;
        }

        let attribute = {};
        if (index === -1) {

          attribute = {...row, iid: editingKey, modelingTemplateTag: null};
          newData.splice(insertIndex, 0, attribute);
          
        } else {
          const item = newData[index];

          attribute = { ...item, ...row, modelingTemplateTag: null };
          newData.splice(index, 1, attribute);
        }

        moveRowRef.current.data = newData;

        onChange && onChange(newData, true);

        if (!attribute.needAttention) {
          preSaveDataModel(attribute);
        }

        setEditingKey('');
        setSuggests([]);
        setEnglishSuggests([]);
      }

      return true;
      
    } catch (errInfo) {
      console.log('Validate Failed:', errInfo);
      return false;
    }
  };

  const onValuesChange = (changedValues, allValues, offset = 1, iid = editingKey) => {
    // console.log('changed values', changedValues);
    // console.log('all values', allValues);

    let ownPrimaryKey = false;
    if (modelerData?.easyDataModelerPrimaryKey) {
      ownPrimaryKey = (modelerData.easyDataModelerPrimaryKey.filter(item => item.name===allValues.name).length>0);
    }

    if (changedValues.hasOwnProperty('cnName') || changedValues.hasOwnProperty('name')) {

      if (offset === 1) {
        setSuggests([]);
      }

      const newData = [...data];
      const index = newData.findIndex((item) => iid === item.iid);

      if (index === -1) {
        newData.splice(0, 0, { iid, ...allValues});
      } else if (index !== -1) {
        const item = newData[index];
        newData.splice(index, 1, { ...item, ...allValues });
      }

      setSuggestHaveMore(false);
      setCurrentChangedValues(changedValues);

      function getSuggest() {
        setLoadingSuggest(true);
        dispatchLatest({
          type: 'datamodel.suggest',
          payload: {
            params: {
              name: allValues.name||'',
              cnName: allValues.cnName||'',
              topN: (offset+perSuggestCount-1),
              offset
            }
          },
          callback: data => {
            setLoadingSuggest(false);

            if (changedValues.hasOwnProperty('cnName')) {
  
              const moreSuggests = (data||[]).length>0?(data[0].suggestions||[]):[];
              const newSuggests = (offset===1 ? moreSuggests : [...suggests, ...moreSuggests]);
  
              if (moreSuggests.length === perSuggestCount) {
                setSuggestHaveMore(true);
              }
  
              setSuggestOffset(newSuggests.length+1);
              setSuggests(newSuggests);
  
            } else if (changedValues.hasOwnProperty('name')) {
              const moreSuggests = (data||[]).length>1?(data[1].suggestions||[]):[];
              const newSuggests = (offset===1 ? moreSuggests : [...suggests, ...moreSuggests]);
  
              if (moreSuggests.length === perSuggestCount) {
                setSuggestHaveMore(true);
              }
  
              setSuggestOffset(newSuggests.length+1);
              setSuggests(newSuggests);
            }
          },
          error: () => {
            setLoadingSuggest(false);
          }
        })
      }

      if (changedValues.hasOwnProperty('cnName')) {
        if (autoTranslateRef.current) {
          dispatchLatest({
            type: 'datamodel.translatePhase',
            payload: {
              params: {
                phaseInChinese: changedValues.cnName,
              }
            },
            callback: data => {
              if ((data?.translated||'') !== '') {
                form.setFieldsValue({ name: data?.translated||'' });
              }
              getSuggest();
            }
          })
        } else {
          getSuggest();
        }
      } else if (changedValues.hasOwnProperty('name')) {
        autoTranslateRef.current(changedValues.name==='');
        getSuggest();
      }

    } else if(changedValues.hasOwnProperty('notNull') ) {
      if (!changedValues.notNull && ownPrimaryKey) {
        showMessage('info', '主键不允许为空');
      }
    } 
     
    if (ownPrimaryKey) {
      form.setFieldsValue({
        notNull: true
      });
    } 

  };

  const onSuggestChange = (record) => {

    form.resetFields();
    form.setFieldsValue({ 
      ...record
    });

    setSuggests([]);
  };

  const editableColumn = [
    ...cols,
    {
      title: '操作',
      dataIndex: 'action',
      width: (action==='flow')?220: ((originAction==='flow')?90:130),
      fixed: 'right',
      render: (_, record) => {
        return (
          <AppContext.Consumer>
          {
            value => <React.Fragment>
            {
              (action==='flow') && <React.Fragment>
              {
                record?.isPossibleNewRecommendedDefinition?.possible && <Typography.Link className='mr-3' onClick={(event) => {
                  event.stopPropagation();  
                  value?.setGlobalState && value?.setGlobalState({
                    message: 'data-govern-show-standard-create',
                    data: {
                      column: record,
                      type: record?.isPossibleNewRecommendedDefinition?.type
                    }
                  });
                }}>
                  加入标准
                </Typography.Link>
              }
              {
                record?.isPossibleNewTerm?.possible && <Typography.Link className='mr-3' onClick={(event) => {
                  event.stopPropagation();  
                  value?.setGlobalState && value?.setGlobalState({
                    message: 'data-govern-show-standard-create',
                    data: {
                      column: record,
                      type: record?.isPossibleNewTerm?.type
                    }
                  })
                }}>
                  加入词汇
                </Typography.Link>
              }
              </React.Fragment>
            }
            {
              editable && <React.Fragment> 
              {
                <React.Fragment>
                  {
                    (originAction!=='flow') && <Tooltip title={record.needAttention ? '取消送审关注': '送审关注'}>
                      <Button 
                        className='mr-3' 
                        size='small'
                        type='text' 
                        icon={record.needAttention ? <AttentionSvg style={{ width: 15, height: 15 }} /> : <UnAttentionSvg style={{ width: 15, height: 15 }} />} 
                        onClick={(event) => { 
                          event.stopPropagation();
                          if (record.needAttention === null) {
                            record.needAttention = true;
                          } else {
                            record.needAttention = !record.needAttention;
                          }

                          const newData = [...moveRowRef.current.data];
    
                          const index = newData.findIndex((item) => record.iid === item.iid);

                          if (index !== -1) {
                            newData.splice(index, 1, {...record});

                            setData(newData);
                            moveRowRef.current.data = newData;
                            onChange && onChange(newData, false);

                            if (!record.needAttention) {
                              preSaveDataModel(record);
                            }
                          }

                  
                        }}
                      />
                    </Tooltip>
                  }
          
                  <Button 
                    className='mr-3' 
                    size='small'
                    type='text' 
                    icon={<PlusOutlined className='default' />} 
                    onClick={(event) => { 
                      event.stopPropagation();
                      insertToFront(record); 
                    }}
                  />

                  <Button 
                    className='mr-3' 
                    size='small'
                    type='text' 
                    icon={<DeleteOutlined style={{ color: 'red' }} />} 
                    onClick={(event) => { 
                      event.stopPropagation();
                      remove(record); 
                    }}
                  />
                </React.Fragment>
              }
              </React.Fragment> 
            }
            </React.Fragment>
          }
          </AppContext.Consumer>
        )
      },
    },
  ]

  const validateColumn = {
    title: '规范',
    dataIndex: 'validate',
    //小屏幕下隐藏规范, 给编辑多点空间
    width: (tableWidth<1300 && editable)?0:200,
    fixed: 'right',
    render: (text, record, index) => {
      let shortCauses = []; 
      let causes = [];
      (validateReports||[]).forEach((report) => {
        if (report.type==='DataModelAttribute' && report.iid === record.iid) {
          (report.reportItems||[]).forEach((item) => {
            shortCauses.push(item.shortCause||'');
            causes.push(item.cause||'');
          })
        }
      });

      return (
        <div className='d-flex' key={index} style={{ alignItems: 'center', justifyContent: 'space-between' }}>
          <div>
          {
            shortCauses && shortCauses.map((shortCause, index) => {
              return (
                <Tooltip title={shortCause}>
                  <div className='textOverflow' style={{ width: 130, color: '#f5222d' }} key={index}>
                    <span>{shortCause||''}</span>
                  </div>
                </Tooltip>
              );
            })
          }
          </div>
          {
            (causes||[]).length>0 && <Popover
              content={
                <div style={{ maxWidth: 200, maxHeight: 200, wordWrap: 'break-word', overflow: 'auto'  }}>
                {
                  causes && causes.map((cause, index) => {
                    return (
                      <Typography.Paragraph key={index} >
                      {cause||''}
                      </Typography.Paragraph>
                    )
                  })
                }
                </div>
              }
              title="规则详情"
            >     
              <a href="#">详情</a>     
            </Popover>
          }
        </div>
      )
    }
  };

  const includeValidateColumn = [
    ...cols,
    validateColumn
  ]

  const includeValidateEditableColumn = [
    ...editableColumn,
    validateColumn
  ]

  const mergedColumns = () => {
    const hasValidateReports = (validateReports||[]).filter(report => report.type==='DataModelAttribute').length>0;

    if (editable) {
      let _columns = hasValidateReports ? includeValidateEditableColumn: editableColumn;

      _columns = _columns.map((col) => {
        if (!col.editable) {
          return col;
        }
    
        return {
          ...col,
          onCell: (record) => ({
            record,
            dataIndex: col.dataIndex,
            inputType:  (col.dataIndex==='notNull' || col.dataIndex==='partOfDistributionKey' || col.dataIndex==='partOfPrimaryKeyLogically' || col.dataIndex==='needAttention' || col.dataIndex==='foreignKey') ? 'check' : 'text',
            colTitle: col.title,
            editing: isEditing(record),
            datatypes: supportedDatatypes,
            require: col.require
          }),
        };
      });

      setColumns(_columns);
    } else {
      let _columns = hasValidateReports ? includeValidateColumn: cols;

      if (action === 'flow') {
        _columns = hasValidateReports ? includeValidateEditableColumn: editableColumn;
      }

      // _columns = _columns.filter((col) => col.dataIndex!=='needAttention');

      setColumns(_columns);
    }
  }

  const moveRow = useCallback(
    (dragIndex, hoverIndex) => {

      const { data, pageNum, pageSize } = moveRowRef.current;

      let realDragIndex = dragIndex;
      let realHoverIndex = hoverIndex;

      if ((data||[]).length>supportMaxAttributeCountPerPage) {
        realDragIndex = (pageNum-1)*pageSize + dragIndex;
        realHoverIndex = (pageNum-1)*pageSize + hoverIndex;
      }

      const dragRow = data[realDragIndex];

      const newData = update(data, {
        $splice: [
          [realDragIndex, 1],
          [realHoverIndex, 0, dragRow],
        ],
      })

      onChange && onChange(newData);
    },
    //eslint-disable-next-line react-hooks/exhaustive-deps
    [moveRowRef.current],
  );

  const onSearchInputChange = (value) => {
    setEditingKey('');

    setKeywordCondition({ keyword: value||'', needFilter: true });
  }

  const loadMoreSuggests = (event) => {
    event.stopPropagation();

    onValuesChange(currentChangedValues, form.getFieldsValue(), suggestOffset);
  }

  const closeSuggests = (event) => {
    event.stopPropagation();

    setSuggestHaveMore(false);
    setSuggests([]);
    setSuggestOffset(1);
  }

  const displayMenu = (e) => {
    show({
      event: e
    })
  }

  const handleItemClick = ({ id, event, props }) => {
    if (id === 'up') {
      insertToFront(currentItem);
    } else if (id === 'down') {
      insertToBack(currentItem);
    }
  }

  const handleResize = index => (e, { size }) => {
    const nextColumns = [...columns];
    nextColumns[index] = {
      ...nextColumns[index],
      width: size.width,
    };

    setColumns(nextColumns);
  };

  const resizeColumns = () => {
    return (
      columns.map((column, index) => { 
        return {
          ...column,
          onHeaderCell: column => ({
            width: column.width,
            onResize: handleResize(index),
          }),
        };
      })
    );
  }

  return (
    <div className='model-import-action-table'>
      <div className='d-flex mb-3' style={{ justifyContent: 'space-between', alignItems: 'center' }}>
        <Space>
          <h2 style={{ marginBottom: 0 }}>数据表结构</h2> 
          { 
            editable && <Popover content={<span>
              新增: 点击操作列的加号按钮在当前字段前新增一个字段<br />
              修改: 点击字段表格中的一行任意位置进入该字段编辑页面<br />
              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;输入中文名，自动推荐英文名，可选择采用或者手工修改<br />
              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;输入中文名，自动推荐可参考引用的数据标准或者数据字典，可选择采用<br />
              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;支持拖拽方式调整模型字段顺序<br />
              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;点击表格外部任意位置退出字段编辑状态<br />
              删除: 点击操作列垃圾桶图标删除该字段<br />
              保存: 页面右下角保存按钮
            </span>}>
              <QuestionCircleOutlined className='pointer' /> 
            </Popover> 
          }
        </Space>
        <Space>
        { 
          editable && <Tooltip> 
            <Button onClick={onAddClick}>新建</Button>
          </Tooltip>  
        }
        <div className='d-flex' style={{ alignItems: 'center' }}>
          <InputDebounce 
            placeholder="请输入中文名称或者英文名称" 
            allowClear 
            value={keyword}
            onChange={onSearchInputChange} 
            style={{ width: inputWidth }}
          />
        </div>
        </Space>
      </div>
      <div className='mb-3' id="containerId" ref={tableRef}>
        <ResizeObserver
          onResize={({ width }) => {
            setTableWidth(width);
          }}
        >
          <DndProvider backend={HTML5Backend} >
            <Form form={form} component={false} onValuesChange={onValuesChange}>
              <Table
                components={{
                  header: {
                    cell: ResizeableHeaderCell,
                  },
                  body: {
                    cell: EditableCell,
                    //编辑或者搜索状态下不允许拖动
                    row: (editable&&editingKey===''&&keyword==='')?DragableBodyRow:null,
                  },
                }}
                rowClassName={(record, index) => {
                  if (type==='model' && record?.modelingTemplateTag && record?.modelingTemplateTag!=={} && !isEditing(record)) {
                    return 'editable-row template-highlight-row';
                  }

                  if (type==='model' && !isEditing(record)) {
                    if (record?.needAttention) {
                      return 'editable-row attention-row';
                    } else if (record?.partOfPrimaryKeyLogically) {
                      return 'editable-row primary-row';
                    }
                  } 

                  return 'editable-row';
                }}
                onRow={(record, index) => {

                  let rowParams = {
                    index,
                    id: `field-${record.iid}`,
                  }

                  if (editable) {
                    rowParams = {...rowParams, onContextMenu: event => {
                        setCurrentItem(record);
                        displayMenu(event);
                      }
                    };

                    if (!isEditing(record)) {
                      rowParams = {...rowParams, onClick: (event) => {
                          event.stopPropagation();
                          edit(record);
                        }
                      }

                      if (keyword.length===0) {
                        rowParams = {...rowParams, moveRow};
                      }
                    }
                  }

                  return rowParams;
                }}
                dataSource={filterPageData||[]}
                columns={resizeColumns()}
                size='small'
                rowKey='iid'
                pagination={false}
                sticky
                scroll={{
                  x: 1500,
                  //解决屏幕尺寸窄时,字段不好横向拖动的问题
                  y: tableWidth>1500?'100%':630,
                }}
                expandable={{
                  columnWidth: 0,
                  expandedRowRender: record => (
                    <React.Fragment>
                    {
                      editingKey!=='' && <React.Fragment>
                      {
                        suggests && suggests.length>0 && (
                          <SuggestTable suggests={suggests} onSelect={onSuggestChange} />
                        )
                      }
                      </React.Fragment>
                    }
                    <div className='flex pt-3' style={{ justifyContent: 'center' }}>
                      <Tooltip title={!suggestHaveMore?'没有更多推荐字段': ''}>
                        <Button onClick={loadMoreSuggests} disabled={!suggestHaveMore} loading={loadingSuggest}>加载更多</Button>
                      </Tooltip>
                      <Button className='ml-3' onClick={closeSuggests}>收起推荐</Button>
                    </div> 

                    </React.Fragment>
                  ),
                  expandIcon: ({ expanded, onExpand, record }) => {
                    return null;
                  },
                  rowExpandable: record => (editingKey!==''&&((suggests||[]).length>0 || (englishSuggests||[]).length>0)),
                  expandedRowKeys: [editingKey]
                }}
              />
            </Form>
          </DndProvider>
        </ResizeObserver>
        {
          (filterData.length > supportMaxAttributeCountPerPage) && <Pagination
            className="text-center mt-3"
            showSizeChanger
            showQuickJumper
            onChange={(_pageNum, _pageSize) => {
              setFilterPageCondition({...filterPageCondition, ...{ pageNum: _pageNum, pageSize: _pageSize || supportMaxAttributeCountPerPage }})
            }}
            onShowSizeChange={(_pageNum, _pageSize) => {
              setFilterPageCondition({...filterPageCondition, ...{ pageNum: _pageNum || 1, pageSize: _pageSize }})
            }}
            current={pageNum}
            pageSize={pageSize}
            defaultCurrent={1}
            total={(filterData||[]).length}
            pageSizeOptions={[50, supportMaxAttributeCountPerPage]}
            showTotal={total => `共 ${(filterData||[]).length} 条`}
          />
        }

        <RcMenu id={MENU_ID} >
          <RcItem id="up" onClick={handleItemClick}>
            在上方插入行
          </RcItem>
          <RcItem id="down" onClick={handleItemClick}>
            在下方插入行
          </RcItem>
        </RcMenu> 
        
      </div>
    </div>
  );
};
