"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.insertFragmentList = exports.getTextAndListItemNodes = void 0;
var _slate = require("slate");
var _slugid = _interopRequireDefault(require("slugid"));
var _core = require("../../../core");
var _constant = require("../constant");
var _elementTypes = require("../../../constants/element-types");
const isListRoot = node => {
  return _slate.Element.isElement(node) && _constant.LIST_TYPES.includes(node.type);
};
const getFirstAncestorOfType = (root, entry, _ref) => {
  let {
    type
  } = _ref;
  let ancestor = _slate.Path.parent(entry[1]);
  while ((0, _core.getNode)(root, ancestor).type !== type) {
    ancestor = _slate.Path.parent(ancestor);
  }
  return [(0, _core.getNode)(root, ancestor), ancestor];
};
const findListItemsWithContent = first => {
  let prev = null;
  let node = first;
  while (isListRoot(node) || node.type === _elementTypes.LIST_ITEM && node.children[0].type !== _elementTypes.PARAGRAPH) {
    prev = node;
    [node] = node.children;
  }
  return prev ? prev.children : [node];
};
const trimList = listRoot => {
  if (!isListRoot(listRoot)) {
    return [listRoot];
  }
  const _texts = _slate.Node.texts(listRoot);
  const textEntries = Array.from(_texts);
  const commonAncestorEntry = textEntries.reduce((commonAncestor, textEntry) => {
    return _slate.Path.isAncestor(commonAncestor[1], textEntry[1]) ? commonAncestor : (0, _core.getCommonNode)(listRoot, textEntry[1], commonAncestor[1]);
  }, getFirstAncestorOfType(listRoot, textEntries[0], {
    type: _elementTypes.LIST_ITEM
  }));

  // is ul/ol: return children
  // is not ul/ol
  const [first, ...rest] = isListRoot(commonAncestorEntry[0]) ? commonAncestorEntry[0].children : [commonAncestorEntry[0]];
  return [...findListItemsWithContent(first), ...rest];
};
const wrapNodeIntoListItem = node => {
  if (node.type === _elementTypes.LIST_ITEM) return node;
  const children = (0, _core.getInlineNodes)(node);
  return {
    id: _slugid.default.nice(),
    type: _elementTypes.LIST_ITEM,
    children: [{
      id: _slugid.default.nice(),
      type: _elementTypes.PARAGRAPH,
      children
    }]
  };
};
const isSingleLic = fragment => {
  const isFragmentOnlyListRoot = fragment.length === 1 && isListRoot(fragment[0]);
  return isFragmentOnlyListRoot && [...(0, _core.getNodes)({
    children: fragment
  })].filter(entry => _slate.Element.isElement(entry[0])).filter(_ref2 => {
    let [node] = _ref2;
    return node.type === _elementTypes.PARAGRAPH;
  }).length === 1;
};
const getTextAndListItemNodes = (editor, fragment, liEntry, licEntry) => {
  const [, liPath] = liEntry;
  const [licNode, licPath] = licEntry;
  const isEmptyNode = !_slate.Node.string(licNode);
  // format copied fragment
  // first: lic, path: [...liPath, 0, 0]
  // rest: children, path: [...liPath, 1, 0]
  const [first, ...rest] = fragment.flatMap(trimList).map(wrapNodeIntoListItem);
  let textNode = null;
  let listItemNodes = [];
  if (isListRoot(fragment[0])) {
    if (isSingleLic(fragment)) {
      textNode = first;
      listItemNodes = rest;
    } else if (isEmptyNode) {
      const li = (0, _core.getNode)(editor, liPath);
      const [, ...currentSubLists] = li.children; // old

      const [newLic, ...newSubLists] = first.children; // copied
      // insert copied contents
      _slate.Transforms.insertNodes(editor, newLic, {
        at: _slate.Path.next(licPath),
        select: true
      });
      _slate.Transforms.removeNodes(editor, {
        at: licPath
      });
      if (newSubLists.length) {
        if (currentSubLists.length) {
          const path = [...liPath, 1, 0];
          _slate.Transforms.insertNodes(editor, newSubLists[0].children, {
            at: path,
            select: true
          });
        } else {
          _slate.Transforms.insertNodes(editor, newSubLists, {
            at: _slate.Path.next(licPath),
            select: true
          });
        }
      }
      textNode = (0, _core.generateDefaultText)();
      listItemNodes = rest;
    } else {
      textNode = (0, _core.generateDefaultText)();
      listItemNodes = [first, ...rest];
    }
  } else {
    textNode = first;
    listItemNodes = rest;
    return {
      textNode,
      listItemNodes
    };
  }
  return {
    textNode,
    listItemNodes
  };
};
exports.getTextAndListItemNodes = getTextAndListItemNodes;
const insertFragmentList = editor => {
  return fragment => {
    _slate.Editor.withoutNormalizing(editor, () => {
      let liEntry = (0, _core.findNode)(editor, {
        match: {
          type: _elementTypes.LIST_ITEM
        },
        mode: 'lowest'
      });
      if (!liEntry) {
        const nodes = isListRoot(fragment) ? [(0, _core.generateDefaultText)(), ...fragment] : fragment;
        return (0, _slate.insertFragment)(editor, nodes);
      }
      (0, _slate.insertFragment)(editor, [(0, _core.generateDefaultText)()]); // need ' '

      liEntry = (0, _core.findNode)(editor, {
        match: {
          type: _elementTypes.LIST_ITEM
        },
        mode: 'lowest'
      });
      const licEntry = (0, _core.findNode)(editor, {
        match: {
          type: _elementTypes.PARAGRAPH
        },
        mode: 'lowest'
      });
      if (!licEntry) {
        const nodes = isListRoot(fragment) ? [(0, _core.generateDefaultText)(), ...fragment] : fragment;
        return (0, _slate.insertFragment)(editor, nodes);
      }
      const {
        textNode,
        listItemNodes
      } = getTextAndListItemNodes(editor, fragment, liEntry, licEntry);
      (0, _slate.insertFragment)(editor, [textNode]);
      const [, liPath] = liEntry;
      return _slate.Transforms.insertNodes(editor, listItemNodes, {
        at: _slate.Path.next(liPath),
        select: true
      });
    });
  };
};
exports.insertFragmentList = insertFragmentList;