import { cloneDeep, isUndefined } from 'lodash-es';
import {
  ComputedRef,
  getCurrentInstance,
  inject,
  reactive,
  ref,
  Ref,
  toRaw,
  UnwrapRef,
  watch,
} from 'vue';
import Schema from 'async-validator';
import { RuleItem, ValidateError } from 'async-validator/dist-types/interface';

export interface TableEdit {
  tableEdit?: Function;
  tableSave?: Function;
  tableCancel?: Function;
  tableDelete?: Function;
  addRow?: Function;
  getKey?: Function;
  validate?: Function;
  getValidate?: Function;
  setValidate?: Function;
  setValue?: Function;
  getValue?: Function;
}

export interface UseTableEdit {
  dataSource: Ref<Recordable[]>;
  columns: ComputedRef<Recordable[]>;
  rowKey: String;
  editable: Ref<Boolean>;
}

export function useTableEdit({ dataSource, columns, rowKey, editable }: UseTableEdit) {
  const instance = getCurrentInstance();
  const emit = instance?.emit;

  const editableData: UnwrapRef<Recordable> = reactive({}); //编辑关联数据
  const validateData: UnwrapRef<Recordable> = reactive({}); //验证数据

  let autoKey = 0;

  function getKey(record: Recordable): string {
    // if (isUndefined(record[rowKey]))
    //   console.error(`rowKey: ${rowKey} not find in ${JSON.stringify(record)}`);
    return record[rowKey];
  }

  function getValue(key?: string, field?: string): any {
    if (!key && !field) {
      //表格编辑 editableData会附加额外的单元格字段
      return dataSource.value;
    } else if (!field) {
      //行编辑
      return editableData[key as string];
    }

    return editableData[key] ? editableData[key][field] : editableData[`${key}_${field}`];
    // 单元格编辑
  }

  function addRow(item = {}) {
    const row = cloneDeep(item);
    row[rowKey] = ++autoKey;
    dataSource.value.push(row);
    console.log('addRow', item);
    console.log('dataSource.value', dataSource.value);

    tableEdit(row[rowKey]);
  }

  function setValue(key: string, val: any, field?: string) {
    if (!field) {
      editableData[key] = val;
    } else {
      editableData[key]
        ? (editableData[key][field] = val)
        : (editableData[`${key}_${field}`] = val);
    }
  }

  function deleteValue(key: string, field?: string) {
    if (!field) {
      delete editableData[key];
    } else {
      delete editableData[`${key}_${field}`];
    }
  }

  function getValidate(key: string, field?: string) {
    if (!field) {
      return validateData[key];
    } else {
      return validateData[`${key}_${field}`];
    }
  }

  function setValidate(key: string, val: any, field?: string) {
    if (!field) {
      validateData[key] = val;
    } else {
      validateData[`${key}_${field}`] = val;
    }
  }

  function deleteValidate(key: string, field?: string) {
    if (!field) {
      delete validateData[key];
    } else {
      delete validateData[`${key}_${field}`];
    }
  }

  const validator: Recordable = {};
  const rules: RuleItem = inject('rules', ref({})).value;

  if (rules.defaultField?.fields) {
    Object.keys(rules.defaultField.fields).forEach(function (key) {
      validator[key] = new Schema({ [key]: rules.defaultField.fields[key] });
    });
  }

  validator['ROW'] = new Schema(rules.defaultField?.fields || {});
  validator['TABLE'] = new Schema({
    table: rules,
  });

  const getValidator = (key = 'ROW') => {
    return validator[key];
  };
  /**
   * 验证行
   * @param key
   */
  const validate = (key?: string, field?: string) => {
    if (!key && !field) {
      return getValidator('TABLE')
        .validate({ table: dataSource.value })
        .then(() => {
          return Promise.resolve();
        })
        .catch(({ errors }: { errors: ValidateError[] }) => {
          return Promise.reject(new Error(errors[0].message));
        });
    } else if (!field) {
      return getValidator('ROW')
        .validate(getValue(key))
        .then(() => {
          return Promise.resolve();
        })
        .catch(({ errors }: { errors: ValidateError[] }) => {
          return Promise.reject(new Error(errors[0].message));
        });
    } else if (key) {
      return getValidator(field)?.validate({ [field]: getValue(key, field) }, (errors) => {
        if (errors) {
          setValidate(key, errors[0], field);
        } else {
          setValidate(key, undefined, field);
        }
      });
    }
  };

  /**
   * 编辑行
   * @param key
   */
  const tableEdit = (key: string, field?: string) => {
    const item = dataSource.value.filter((item) => key === item[rowKey as keyof Recordable])[0];

    if (!field) {
      const validateItem: Recordable = {};
      Object.keys(item).forEach((field) => (validateItem[field] = undefined));
      setValidate(key, validateItem);

      // 表格编辑时为引用,否则为深拷贝
      if (editable.value) {
        setValue(key, item);
      } else {
        setValue(key, cloneDeep(item));
      }
    } else {
      setValue(key, item[field], field);
      setValidate(key, undefined, field);
    }
  };

  /**
   * 保存
   * @param key
   */
  const tableSave = (key: string, field?: string) => {
    const data = dataSource.value.filter(
      (item: Recordable) => key === item[rowKey as keyof Recordable]
    )[0];
    if (!field) {
      Object.assign(data, getValue(key));
      deleteValue(key);
      deleteValidate(key);
    } else {
      data[field] = getValue(key, field);
      emit?.('cellChange', { field, value: data[field], key, record: toRaw(data) });
      deleteValue(key, field);
      deleteValidate(key, field);
    }
  };

  const tableDelete = (key: string) => {
    console.log('tableDelete', key);
    deleteValue(key);
    deleteValidate(key);

    dataSource.value.splice(
      dataSource.value.findIndex((item) => item[rowKey] === key),
      1
    );
  };

  /**
   * 取消编辑
   * @param key
   */
  const tableCancel = (key: string, field?: string) => {
    if (field) {
      deleteValue(key);
    } else {
      deleteValue(key, field);
    }
  };

  /**
   * 设置dataSource111
   * @param data
   */

  watch(
    () => dataSource.value,
    (val, prev) => {
      // console.log(val, prev);
      if (editable.value) {
        Object.keys(editableData).forEach((key) => {
          delete editableData[key];
        });
        Object.keys(validateData).forEach((key) => {
          delete validateData[key];
        });
        console.log('dataSource.value', dataSource.value);
        dataSource.value.forEach((item) => {
          item[rowKey] = ++autoKey;
          tableEdit(item[rowKey as keyof Recordable]);
        });
      }
    },
    {
      immediate: true,
    }
  );
  return {
    tableEdit,
    tableSave,
    tableCancel,
    tableDelete,
    addRow,
    getKey,
    validate,
    getValidate,
    setValidate,
    setValue,
    getValue,
  };
}