import "core-js/modules/es.array.iterator.js";
import "core-js/modules/web.dom-collections.iterator.js";
import "core-js/modules/es.promise.js";
/* eslint-disable camelcase */
import React, { useCallback, useMemo, useRef, useState } from 'react';
import useMergedState from 'rc-util/es/hooks/useMergedState';
import useLazyKVMap from 'antd/es/table/hooks/useLazyKVMap';
import { LoadingOutlined } from '@ant-design/icons';
import ReactDOM from 'react-dom';
import set from 'rc-util/es/utils/set';
import message from '../../message';
import Popconfirm from '../../popconfirm';
import { useIntl } from '../../wau-provider';
import useMountMergeState from '../useMountMergeState';
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
export const toNumber = recordKey => {
  if (recordKey.startsWith('0')) {
    return recordKey;
  }
  return Number.isNaN(recordKey) ? recordKey : Number(recordKey);
};
export const recordKeyToString = rowKey => {
  if (Array.isArray(rowKey)) return rowKey.join(',');
  return rowKey;
};
/**
 * 使用map 来删除数据，性能一般 但是准确率比较高
 *
 * @param params
 * @param action
 */
function editableRowByKey(params, action) {
  const {
    getRowKey,
    row,
    data,
    childrenColumnName
  } = params;
  const key = recordKeyToString(params.key);
  const kvMap = new Map();

  /**
   * 打平这个数组
   *
   * @param records
   * @param parentKey
   */
  function dig(records, map_row_parentKey) {
    records.forEach((record, index) => {
      const recordKey = getRowKey(record, index);
      // children 取在前面方便拼的时候按照反顺序放回去
      if (record && typeof record === 'object' && childrenColumnName in record) {
        dig(record[childrenColumnName] || [], recordKey);
      }
      const newRecord = {
        ...record,
        map_row_key: recordKey,
        children: undefined,
        map_row_parentKey
      };
      delete newRecord.children;
      if (!map_row_parentKey) {
        delete newRecord.map_row_parentKey;
      }
      kvMap.set(recordKey, newRecord);
    });
  }
  dig(data);
  if (action === 'update') {
    kvMap.set(key, {
      ...kvMap.get(key),
      ...row
    });
  }
  if (action === 'delete') {
    kvMap.delete(key);
  }
  const fill = map => {
    const kvArrayMap = new Map();
    const kvSource = [];
    map.forEach(value => {
      if (value.map_row_parentKey) {
        // @ts-ignore
        const {
          map_row_parentKey,
          map_row_key,
          ...reset
        } = value;
        if (kvArrayMap.has(map_row_key)) {
          reset[childrenColumnName] = kvArrayMap.get(map_row_key);
        }
        kvArrayMap.set(map_row_parentKey, [...(kvArrayMap.get(map_row_parentKey) || []), reset]);
        return;
      }
      if (!value.map_row_parentKey) {
        // @ts-ignore
        const {
          map_row_key,
          ...rest
        } = value;
        if (kvArrayMap.has(map_row_key)) {
          const item = {
            ...rest,
            [childrenColumnName]: kvArrayMap.get(map_row_key)
          };
          kvSource.push(item);
          return;
        }
        kvSource.push(rest);
      }
    });
    return kvSource;
  };
  const source = fill(kvMap);
  return source;
}

/**
 * 保存按钮的dom
 *
 * @param ActionRenderConfig
 */
export const SaveEditableAction = ({
  recordKey,
  onSave,
  form,
  row,
  children,
  newLineConfig,
  editorType
}) => {
  const [loading, setLoading] = useMountMergeState(false);
  return /*#__PURE__*/_jsxs("a", {
    onClick: async () => {
      try {
        const isMapEditor = editorType === 'Map';
        const namePath = Array.isArray(recordKey) ? recordKey : [recordKey];
        setLoading(true);
        await form.validateFields(namePath, {
          // @ts-expect-error
          recursive: true
        });
        const fields = form.getFieldValue(namePath);
        const record = isMapEditor ? set(row, namePath, fields) : {
          ...row,
          ...fields
        };
        const res = await (onSave === null || onSave === void 0 ? void 0 : onSave(recordKey, record, newLineConfig));
        setLoading(false);
        return res;
      } catch (e) {
        // eslint-disable-next-line no-console
        console.log(e);
        setLoading(false);
        return null;
      }
    },
    children: [loading ? /*#__PURE__*/_jsx(LoadingOutlined, {
      style: {
        marginRight: 8
      }
    }) : null, children || '保存']
  }, "save");
};

/**
 * 删除按钮 dom
 *
 * @param ActionRenderConfig
 */
export const DeleteEditableAction = ({
  recordKey,
  onDelete,
  row,
  children,
  deletePopconfirmMessage,
  cancelEditable
}) => {
  const [loading, setLoading] = useMountMergeState(false);
  const onConfirm = async () => {
    try {
      setLoading(true);
      const res = await (onDelete === null || onDelete === void 0 ? void 0 : onDelete(recordKey, row));
      setLoading(false);
      setTimeout(() => {
        cancelEditable(recordKey);
      }, 0);
      return res;
    } catch (e) {
      // eslint-disable-next-line no-console
      console.log(e);
      setLoading(false);
      return null;
    }
  };
  return children !== false ? /*#__PURE__*/_jsx(Popconfirm, {
    title: deletePopconfirmMessage,
    onConfirm: onConfirm,
    children: /*#__PURE__*/_jsxs("a", {
      children: [loading ? /*#__PURE__*/_jsx(LoadingOutlined, {
        style: {
          marginRight: 8
        }
      }) : null, children || '删除']
    })
  }, "delete") : null;
};
export function defaultActionRender(row, config) {
  const {
    recordKey,
    newLineConfig,
    form,
    onCancel,
    cancelEditable,
    saveText,
    cancelText,
    deleteText
  } = config;
  return [/*#__PURE__*/_jsx(SaveEditableAction, {
    ...config,
    row: row,
    children: saveText
  }, "save"), (newLineConfig === null || newLineConfig === void 0 ? void 0 : newLineConfig.options.recordKey) !== recordKey ? /*#__PURE__*/_jsx(DeleteEditableAction, {
    ...config,
    row: row,
    children: deleteText
  }, "delete") : null, /*#__PURE__*/_jsx("a", {
    onClick: async () => {
      const namePath = Array.isArray(recordKey) ? recordKey : [recordKey];
      const fields = form.getFieldValue(namePath);
      const res = await (onCancel === null || onCancel === void 0 ? void 0 : onCancel(recordKey, fields, newLineConfig));
      cancelEditable(recordKey);
      return res;
    },
    children: cancelText || '取消'
  }, "cancel")];
}

/**
 * 一个方便的hooks 用于维护编辑的状态
 *
 * @param props
 */
function useEditableArray(props) {
  const [newLineRecord, setNewLineRecord] = useState(undefined);
  const newLineRecordRef = useRef(undefined);

  // 这里这么做是为了存上次的状态，不然每次存一下再拿
  newLineRecordRef.current = newLineRecord;
  const editableType = props.type || 'single';
  const [getRecordByKey] = useLazyKVMap(props.dataSource, 'children', props.getRowKey);
  const [editableKeys, setEditableRowKeys] = useMergedState([], {
    value: props.editableKeys,
    onChange: props.onChange ? keys => {
      var _props$onChange;
      props === null || props === void 0 || (_props$onChange = props.onChange) === null || _props$onChange === void 0 ? void 0 : _props$onChange.call(props,
      // 计算编辑的key
      keys,
      // 计算编辑的行
      keys.map(key => getRecordByKey(key)));
    } : undefined
  });
  /** 一个用来标志的set 提供了方便的 api 来去重什么的 */
  const editableKeysSet = useMemo(() => {
    const keys = editableType === 'single' ? editableKeys.slice(0, 1) : editableKeys;
    return new Set(keys);
  }, [editableKeys.join(','), editableType]);

  /** 这行是不是编辑状态 */
  const isEditable = useCallback(row => {
    const recordKey = props.getRowKey(row, row.index);
    if (editableKeys.includes(recordKey)) return {
      recordKey,
      isEditable: true
    };
    return {
      recordKey,
      isEditable: false
    };
  }, [editableKeys.join(',')]);

  /**
   * 进入编辑状态
   *
   * @param recordKey
   */
  const startEditable = recordKey => {
    // 如果是单行的话，不允许多行编辑
    if (editableKeysSet.size > 0 && editableType === 'single') {
      message.warn(props.onlyOneLineEditorAlertMessage || '只能同时编辑一行');
      return false;
    }
    editableKeysSet.add(recordKey);
    setEditableRowKeys(Array.from(editableKeysSet));
    return true;
  };

  /**
   * 退出编辑状态
   *
   * @param recordKey
   */
  const cancelEditable = recordKey => {
    // 防止多次渲染
    ReactDOM.unstable_batchedUpdates(() => {
      /** 如果这个是 new Line 直接删除 */
      if (newLineRecord && newLineRecord.options.recordKey === recordKey) {
        setNewLineRecord(undefined);
      }
      editableKeysSet.delete(recordKeyToString(recordKey));
      setEditableRowKeys(Array.from(editableKeysSet));
    });
    return true;
  };
  const onValuesChange = (value, values) => {
    if (!props.onValuesChange) {
      return;
    }
    let {
      dataSource
    } = props;
    // 这里是把正在编辑中的所有表单数据都修改掉
    // 不然会用 props 里面的 dataSource，数据只有正在编辑中的
    Object.keys(values).forEach(recordKey => {
      const editRow = values[recordKey];
      dataSource = editableRowByKey({
        data: dataSource,
        getRowKey: props.getRowKey,
        row: editRow,
        key: toNumber(recordKey),
        childrenColumnName: props.childrenColumnName || 'children'
      }, 'update');
    });
    const recordKey = toNumber(Object.keys(value).pop());
    if (recordKey === (newLineRecord === null || newLineRecord === void 0 ? void 0 : newLineRecord.options.recordKey)) {
      cancelEditable(recordKey);
      startEditable(recordKey);
    }
    const editRow = dataSource.find((item, index) => {
      const key = props.getRowKey(item, index);
      return key === recordKey;
    }) || {
      ...(newLineRecord === null || newLineRecord === void 0 ? void 0 : newLineRecord.defaultValue),
      ...values[recordKey]
    };
    props.onValuesChange(editRow, dataSource);
  };

  /**
   * 同时只能支持一行,取消之后数据消息，不会触发 dataSource
   *
   * @param row
   * @param options
   * @name 增加新的行
   */
  const addEditRecord = (row, options) => {
    // 暂时不支持多行新增
    if (newLineRecordRef.current) {
      message.warn(props.onlyAddOneLineAlertMessage || '只能新增一行');
      return false;
    }
    // 如果是单行的话，不允许多行编辑
    if (editableKeysSet.size > 0 && editableType === 'single') {
      message.warn(props.onlyOneLineEditorAlertMessage || '只能同时编辑一行');
      return false;
    }

    // 防止多次渲染
    ReactDOM.unstable_batchedUpdates(() => {
      const recordKey = props.getRowKey(row, props.dataSource.length);
      editableKeysSet.add(recordKey);
      setEditableRowKeys(Array.from(editableKeysSet));
      if ((options === null || options === void 0 ? void 0 : options.newRecordType) === 'dataSource') {
        var _props$setDataSource;
        (_props$setDataSource = props.setDataSource) === null || _props$setDataSource === void 0 ? void 0 : _props$setDataSource.call(props, [...props.dataSource, row]);
      } else {
        setNewLineRecord({
          defaultValue: row,
          options: {
            ...options,
            recordKey
          }
        });
      }
    });
    return true;
  };

  // Internationalization
  const intl = useIntl();
  const saveText = intl.getMessage('editableTable.action.save', '保存');
  const deleteText = intl.getMessage('editableTable.action.delete', '删除');
  const cancelText = intl.getMessage('editableTable.action.cancel', '取消');
  const actionRender = (row, form) => {
    const key = props.getRowKey(row, row.index);
    const config = {
      saveText,
      cancelText,
      deleteText,
      addEditRecord,
      recordKey: key,
      cancelEditable,
      index: row.index,
      newLineConfig: newLineRecord,
      onCancel: async (recordKey, editRow, isNewLine) => {
        var _props$onCancel;
        const res = await (props === null || props === void 0 || (_props$onCancel = props.onCancel) === null || _props$onCancel === void 0 ? void 0 : _props$onCancel.call(props, recordKey, editRow, isNewLine));
        return res;
      },
      onDelete: async (recordKey, editRow) => {
        var _props$onDelete;
        const actionProps = {
          data: props.dataSource,
          getRowKey: props.getRowKey,
          row: editRow,
          key: recordKey,
          childrenColumnName: props.childrenColumnName || 'children'
        };
        const res = await (props === null || props === void 0 || (_props$onDelete = props.onDelete) === null || _props$onDelete === void 0 ? void 0 : _props$onDelete.call(props, recordKey, editRow));
        props.setDataSource(editableRowByKey(actionProps, 'delete'));
        return res;
      },
      onSave: async (recordKey, editRow, isNewLine) => {
        var _props$onSave;
        const {
          options
        } = isNewLine || {};
        const res = await (props === null || props === void 0 || (_props$onSave = props.onSave) === null || _props$onSave === void 0 ? void 0 : _props$onSave.call(props, recordKey, editRow, isNewLine));
        cancelEditable(recordKey);
        if (isNewLine) {
          if ((options === null || options === void 0 ? void 0 : options.position) === 'top') {
            props.setDataSource([editRow, ...props.dataSource]);
          } else {
            props.setDataSource([...props.dataSource, editRow]);
          }
          return res;
        }
        const actionProps = {
          data: props.dataSource,
          getRowKey: props.getRowKey,
          row: editRow,
          key: recordKey,
          childrenColumnName: props.childrenColumnName || 'children'
        };
        props.setDataSource(editableRowByKey(actionProps, 'update'));
        return res;
      },
      form,
      editableKeys,
      setEditableRowKeys,
      deletePopconfirmMessage: props.deletePopconfirmMessage || '删除此行？'
    };
    const defaultDoms = defaultActionRender(row, config);
    if (props.actionRender) return props.actionRender(row, config, {
      save: defaultDoms[0],
      delete: defaultDoms[1],
      cancel: defaultDoms[2]
    });
    return defaultDoms;
  };
  return {
    editableKeys,
    setEditableRowKeys,
    isEditable,
    actionRender,
    startEditable,
    cancelEditable,
    addEditRecord,
    newLineRecord,
    onValuesChange
  };
}
export default useEditableArray;