import isPlainObject from 'lodash/isPlainObject';
import produce, { setAutoFreeze, Draft } from 'immer';
setAutoFreeze(false);
/**
 * 按key更新obj
 *
 * @param {*} key
 * @param {*} newObj
 * @param {*} table
 */
export function updateByKey(key, newObj, table) {
  return {
    ...table,
    [key]: {
      ...table[key],
      ...newObj
    }
  };
}

/**
 * 按keyname更新obj
 *
 * @example
 * updateByKeyname({id: '1', name: 10}, 'id', {})
 * ==> {'1': {id: '1', name: 10}}
 *
 * @param {*} keyName
 * @param {*} newObjs
 * @param {*} table
 */
export function updateByKeyname(keyName, newObjs, table) {
  if (isPlainObject(newObjs)) {
    newObjs = [newObjs];
  }
  return newObjs.reduce((acc, curr) => {
    const id = curr[keyName];
    return updateByKey(id, curr, acc);
  }, table);
}

/**
 * 深层合并部分数据
 *
 * @example
 * deepUpdate({a: { b: { c: 15, e: 20 }}}, { a: { b: { c: 10, d: 3}}})
 * ==> {a: { b: { c: 15, d: 3, e: 20 }}}
 *
 * @param {*} partialData
 * @param {*} source
 */
export function deepUpdate(partialData, source) {
  if (!source) {
    return source;
  }

  return produce(source, (draft) => {
    Object.keys(partialData).forEach((key) => {
      const value = partialData[key];
      const originValue = draft[key];
      if (isPlainObject(value) && isPlainObject(originValue)) {
        draft[key] = deepUpdate(value, originValue);
        return;
      }
      if (partialData[key] === undefined) return;
      draft[key] = partialData[key];
    });
    return draft;
  });
}

export function deleteByKey<T>(ids, table: T) {
  if (!Array.isArray(ids)) ids = [ids];
  return produce(table, (draft) => {
    ids.forEach((id) => delete draft[id]);
    return draft;
  });
}

/**
 * 把嵌套数组展开成平级
 * @param {*} list
 * @param {*} loopCheckFn 返回需要继续展开的数组
 * @param {*} callback 类似前序递归回调 返回false停止当前分支继续向下递归 返回stop停止递归
 */
export function arrayExpand(list: any = [], loopCheckFn, callback) {
  const _callback =
    callback ||
    function arrayExpandDefaultCallback() {
      return true;
    };
  return list.every(function arrayExpandEvery(item) {
    const r = _callback(item);
    if (r === false) return true;
    if (r === 'stop') return false;
    const value: any = loopCheckFn(item);
    if (Array.isArray(value) && value.length) {
      return arrayExpand(value, loopCheckFn, _callback);
    }
    return true;
  });
}

export function arrayCompeletlyContain(includes, list) {
  return includes.every((id) => !!~list.indexOf(id));
}

export function arrayCompeletlyNotContain(includes, list) {
  return includes.every((id) => !~list.indexOf(id));
}
