"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.transformToTaskList = exports.transformTaskListToBlockNodes = exports.transformSliceEnsureListItemParagraphFirst = exports.transformListStructure = exports.transformListRecursively = exports.transformBetweenListTypes = exports.getFormattedNode = exports.createBlockTaskItem = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _model = require("@atlaskit/editor-prosemirror/model");
var _utils = require("@atlaskit/editor-prosemirror/utils");
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
var _slice2 = require("../utils/slice");
var _listUtils = require("./list-utils");
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var getContentSupportChecker = function getContentSupportChecker(targetNodeType) {
  return function (node) {
    try {
      return targetNodeType.validContent(_model.Fragment.from(node));
    } catch (_unused) {
      return false;
    }
  };
};
var createBlockTaskItem = exports.createBlockTaskItem = function createBlockTaskItem(_ref) {
  var attrs = _ref.attrs,
    content = _ref.content,
    marks = _ref.marks,
    schema = _ref.schema;
  var _schema$nodes = schema.nodes,
    blockTaskItem = _schema$nodes.blockTaskItem,
    paragraph = _schema$nodes.paragraph;
  var newParagraph = paragraph.createChecked(null, content, marks === null || marks === void 0 ? void 0 : marks.filter(function (mark) {
    return blockTaskItem.allowsMarkType(mark.type);
  }));
  return blockTaskItem.create(attrs !== null && attrs !== void 0 ? attrs : null, newParagraph);
};
var _transformListRecursively = exports.transformListRecursively = function transformListRecursively(props, onhandleUnsupportedContent) {
  var transformedItems = [];
  var listNode = props.listNode,
    isSourceBulletOrOrdered = props.isSourceBulletOrOrdered,
    isTargetBulletOrOrdered = props.isTargetBulletOrOrdered,
    isSourceTask = props.isSourceTask,
    isTargetTask = props.isTargetTask,
    supportedListTypes = props.supportedListTypes,
    schema = props.schema,
    targetNodeType = props.targetNodeType;
  var _schema$nodes2 = schema.nodes,
    taskList = _schema$nodes2.taskList,
    listItem = _schema$nodes2.listItem,
    taskItem = _schema$nodes2.taskItem,
    paragraph = _schema$nodes2.paragraph,
    blockTaskItem = _schema$nodes2.blockTaskItem;

  // gating behind platform_editor_small_font_size to support task lists with font size applied,
  // but keep this solution general
  var isBlockTaskEnabled = !!blockTaskItem && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true);

  /**
   * Extracts paragraph children from a blockTaskItem, preserving their marks.
   */
  var extractParagraphsFromBlockTaskItem = function extractParagraphsFromBlockTaskItem(node) {
    var paragraphs = [];
    node.forEach(function (child) {
      if (child.type === paragraph) {
        paragraphs.push(child);
      }
    });
    return paragraphs;
  };
  listNode.forEach(function (child) {
    if (isSourceBulletOrOrdered && isTargetTask) {
      // Convert bullet/ordered => task
      if (child.type === listItem) {
        var inlineContent = [];
        var nestedTaskLists = [];
        var blockMarks = [];
        child.forEach(function (grandChild) {
          if (supportedListTypes.has(grandChild.type) && grandChild.type !== taskList) {
            nestedTaskLists.push(_transformListRecursively(_objectSpread(_objectSpread({}, props), {}, {
              listNode: grandChild
            }), onhandleUnsupportedContent));
          } else if (!getContentSupportChecker(taskItem)(grandChild) && !grandChild.isTextblock) {
            onhandleUnsupportedContent === null || onhandleUnsupportedContent === void 0 || onhandleUnsupportedContent(grandChild);
          } else {
            if (isBlockTaskEnabled && grandChild.type === paragraph && grandChild.marks.length > 0) {
              blockMarks = grandChild.marks;
            }
            inlineContent.push.apply(inlineContent, (0, _toConsumableArray2.default)((0, _listUtils.convertBlockToInlineContent)(grandChild, schema)));
          }
        });
        if (isBlockTaskEnabled && blockMarks.length > 0) {
          transformedItems.push(createBlockTaskItem({
            content: inlineContent,
            marks: blockMarks,
            schema: schema
          }));
        } else {
          transformedItems.push(taskItem.create(null, inlineContent.length > 0 ? inlineContent : null));
        }
        transformedItems.push.apply(transformedItems, nestedTaskLists);
      }
    } else if (isSourceTask && isTargetBulletOrOrdered) {
      // Convert task => bullet/ordered
      if (child.type === taskItem) {
        var _inlineContent = (0, _toConsumableArray2.default)(child.content.content);

        // Transfer taskItem's block marks to the paragraph.
        // Use listItem.allowsMarkType since the paragraph will be inside a listItem
        // (which uses ParagraphWithFontSizeStage0 that allows fontSize).
        var paragraphMarks = isBlockTaskEnabled && child.marks.length > 0 ? child.marks.filter(function (mark) {
          return listItem.allowsMarkType(mark.type);
        }) : undefined;
        var paragraphNode = paragraph.create(null, _inlineContent.length > 0 ? _inlineContent : null, paragraphMarks);
        transformedItems.push(listItem.create(null, [paragraphNode]));
      } else if (isBlockTaskEnabled && child.type === blockTaskItem) {
        // blockTaskItem wraps content in paragraphs — extract them directly,
        // preserving their fontSize marks
        var paragraphs = extractParagraphsFromBlockTaskItem(child);
        if (paragraphs.length > 0) {
          transformedItems.push(listItem.create(null, paragraphs));
        }
      } else if (child.type === taskList) {
        var transformedNestedList = _transformListRecursively(_objectSpread(_objectSpread({}, props), {}, {
          listNode: child
        }), onhandleUnsupportedContent);
        var lastItem = transformedItems[transformedItems.length - 1];
        if ((lastItem === null || lastItem === void 0 ? void 0 : lastItem.type) === listItem) {
          // Attach nested list to previous item
          var updatedContent = [].concat((0, _toConsumableArray2.default)(lastItem.content.content), [transformedNestedList]);
          transformedItems[transformedItems.length - 1] = listItem.create(lastItem.attrs, updatedContent);
        } else {
          // No previous item, flatten nested items
          transformedItems.push.apply(transformedItems, (0, _toConsumableArray2.default)(transformedNestedList.content.content));
        }
      }
    } else if (isSourceBulletOrOrdered && isTargetBulletOrOrdered) {
      if (child.type === listItem) {
        var convertedNestedLists = [];
        child.forEach(function (grandChild) {
          if (supportedListTypes.has(grandChild.type) && grandChild.type !== targetNodeType) {
            var convertedNode = _transformListRecursively(_objectSpread(_objectSpread({}, props), {}, {
              listNode: grandChild
            }), onhandleUnsupportedContent);
            convertedNestedLists.push(convertedNode);
          } else {
            convertedNestedLists.push(grandChild);
          }
        });
        transformedItems.push(listItem.create(null, convertedNestedLists));
      }
    }
  });
  return targetNodeType.create(null, transformedItems);
};

/**
 * Transform list structure between different list types
 */
var transformListStructure = exports.transformListStructure = function transformListStructure(context) {
  var tr = context.tr,
    sourceNode = context.sourceNode,
    sourcePos = context.sourcePos,
    targetNodeType = context.targetNodeType;
  var nodes = tr.doc.type.schema.nodes;
  var unsupportedContent = [];
  var onhandleUnsupportedContent = function onhandleUnsupportedContent(content) {
    unsupportedContent.push(content);
  };
  try {
    var listNode = {
      node: sourceNode,
      pos: sourcePos
    };
    var sourceList = listNode.node,
      listPos = listNode.pos;
    // const { taskList, listItem, taskItem, paragraph } = nodes;

    var isSourceBulletOrOrdered = (0, _listUtils.isBulletOrOrderedList)(sourceList.type);
    var isTargetTask = (0, _listUtils.isTaskList)(targetNodeType);
    var isSourceTask = (0, _listUtils.isTaskList)(sourceList.type);
    var isTargetBulletOrOrdered = (0, _listUtils.isBulletOrOrderedList)(targetNodeType);
    var supportedListTypes = (0, _listUtils.getSupportedListTypesSet)(nodes);
    var newList = _transformListRecursively({
      isSourceBulletOrOrdered: isSourceBulletOrOrdered,
      isSourceTask: isSourceTask,
      isTargetBulletOrOrdered: isTargetBulletOrOrdered,
      isTargetTask: isTargetTask,
      listNode: sourceList,
      schema: tr.doc.type.schema,
      supportedListTypes: supportedListTypes,
      targetNodeType: targetNodeType
    }, onhandleUnsupportedContent);
    tr.replaceWith(listPos, listPos + sourceList.nodeSize, [newList].concat(unsupportedContent));
    return tr;
  } catch (_unused2) {
    return tr;
  }
};

/**
 * Transform between different list types
 */
var transformBetweenListTypes = exports.transformBetweenListTypes = function transformBetweenListTypes(context) {
  var tr = context.tr,
    sourceNode = context.sourceNode,
    sourcePos = context.sourcePos,
    targetNodeType = context.targetNodeType;
  var nodes = tr.doc.type.schema.nodes;
  var sourceListType = sourceNode.type;
  var isSourceBulletOrOrdered = (0, _listUtils.isBulletOrOrderedList)(sourceListType);
  var isTargetTask = (0, _listUtils.isTaskList)(targetNodeType);
  var isSourceTask = (0, _listUtils.isTaskList)(sourceListType);
  var isTargetBulletOrOrdered = (0, _listUtils.isBulletOrOrderedList)(targetNodeType);

  // Check if we need structure transformation
  var needsStructureTransform = isSourceBulletOrOrdered && isTargetTask || isSourceTask && isTargetBulletOrOrdered;
  try {
    if (!needsStructureTransform) {
      // Simple type change for same structure lists (bullet <-> ordered)
      // Apply to the main list
      tr.setNodeMarkup(sourcePos, targetNodeType);

      // Apply to nested lists
      var listStart = sourcePos;
      var listEnd = sourcePos + sourceNode.nodeSize;
      var supportedListTypesSet = (0, _listUtils.getSupportedListTypesSet)(nodes);
      tr.doc.nodesBetween(listStart, listEnd, function (node, pos, parent) {
        // Only process nested lists (not the root list we already handled)
        if (supportedListTypesSet.has(node.type) && pos !== sourcePos) {
          var isNestedList = parent && (supportedListTypesSet.has(parent.type) || parent.type === nodes.listItem);
          if (isNestedList) {
            var shouldTransformNode = node.type === sourceListType || (0, _listUtils.isBulletOrOrderedList)(node.type) && isTargetBulletOrOrdered;
            if (shouldTransformNode) {
              tr.setNodeMarkup(pos, targetNodeType);
            }
          }
        }
        return true; // Continue traversing
      });
      return tr;
    } else {
      return transformListStructure(context);
    }
  } catch (_unused3) {
    return null;
  }
};

/**
 * Transform selection to task list
 * Handles the special structure where taskItem contains text directly (no paragraph wrapper)
 */
var transformToTaskList = exports.transformToTaskList = function transformToTaskList(tr, range, targetNodeType, targetAttrs, nodes) {
  try {
    var taskItem = nodes.taskItem,
      paragraph = nodes.paragraph,
      blockTaskItem = nodes.blockTaskItem;
    // gating behind platform_editor_small_font_size to support task lists with font size applied,
    // but keep this solution general
    var isBlockTaskItemEnabled = !!blockTaskItem && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true);
    var listItems = [];

    // Process each block in the range
    tr.doc.nodesBetween(range.start, range.end, function (node) {
      if (node.isBlock) {
        var inlineContent = (0, _toConsumableArray2.default)(node.content.content);
        if (inlineContent.length > 0) {
          if (isBlockTaskItemEnabled && node.type === paragraph && node.marks.length > 0) {
            listItems.push(createBlockTaskItem({
              attrs: targetAttrs,
              content: inlineContent,
              marks: node.marks,
              schema: tr.doc.type.schema
            }));
          } else {
            listItems.push(taskItem.create(targetAttrs, inlineContent));
          }
        }
      }
      return false;
    });
    if (listItems.length === 0) {
      return null;
    }

    // Create the new task list
    var newList = targetNodeType.create(targetAttrs, listItems);

    // Replace the range with the new list
    tr.replaceWith(range.start, range.end, newList);
    return tr;
  } catch (_unused4) {
    return null;
  }
};
var transformTaskListToBlockNodes = exports.transformTaskListToBlockNodes = function transformTaskListToBlockNodes(context) {
  var tr = context.tr,
    targetNodeType = context.targetNodeType,
    targetAttrs = context.targetAttrs,
    sourceNode = context.sourceNode,
    sourcePos = context.sourcePos;
  var selection = tr.selection;
  var schema = selection.$from.doc.type.schema;
  var blockTaskItem = schema.nodes.blockTaskItem;

  // gating behind platform_editor_small_font_size to support task lists with font size applied,
  // but keep this solution general
  var isBlockTaskItemEnabled = !!blockTaskItem && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true);
  if (isBlockTaskItemEnabled) {
    var blockTaskItemsResult = (0, _utils.findChildrenByType)(sourceNode, blockTaskItem);
    if (blockTaskItemsResult.length > 0 && targetNodeType === schema.nodes.paragraph) {
      // blockTaskItem content is (paragraph | extension)+
      // Extract paragraph children directly — they may carry block marks (e.g. fontSize)
      var _targetNodes = [];
      var _iterator = _createForOfIteratorHelper(blockTaskItemsResult),
        _step;
      try {
        for (_iterator.s(); !(_step = _iterator.n()).done;) {
          var blockItem = _step.value.node;
          blockItem.forEach(function (child) {
            if (child.type === schema.nodes.paragraph) {
              _targetNodes.push(child);
            }
          });
        }
      } catch (err) {
        _iterator.e(err);
      } finally {
        _iterator.f();
      }
      if (_targetNodes.length === 0) {
        return null;
      }
      var _slice = new _model.Slice(_model.Fragment.fromArray(_targetNodes), 0, 0);
      var _rangeStart = sourcePos !== null ? sourcePos : selection.from;
      tr.replaceRange(_rangeStart, _rangeStart + sourceNode.nodeSize, _slice);
      return tr;
    }
  }

  // Original logic for regular taskItem children
  var taskItemsResult = (0, _utils.findChildrenByType)(sourceNode, schema.nodes.taskItem);
  var taskItems = taskItemsResult.map(function (item) {
    return item.node;
  });
  var taskItemFragments = taskItems.map(function (taskItem) {
    return taskItem.content;
  });
  var targetNodes = [];

  // Convert fragments to headings if target is heading
  if (targetNodeType === schema.nodes.heading && targetAttrs) {
    // convert the fragments to headings
    var targetHeadingLevel = targetAttrs.level;
    targetNodes = taskItemFragments.map(function (fragment) {
      return schema.nodes.heading.createChecked({
        level: targetHeadingLevel
      }, fragment.content);
    });
  }

  // Convert fragments to paragraphs if target is paragraphs
  if (targetNodeType === schema.nodes.paragraph) {
    // convert the fragments to paragraphs
    targetNodes = taskItemFragments.map(function (fragment) {
      return schema.nodes.paragraph.createChecked({}, fragment.content);
    });
  }

  // Convert fragments to code block if target is code block
  if (targetNodeType === schema.nodes.codeBlock) {
    // convert the fragments to one code block
    var codeBlockContent = taskItemFragments.map(function (fragment) {
      return fragment.textBetween(0, fragment.size, '\n');
    }).join('\n');
    targetNodes = [schema.nodes.codeBlock.createChecked({}, schema.text(codeBlockContent))];
  }

  // Replace the task list node with the new content in the transaction
  var slice = new _model.Slice(_model.Fragment.fromArray(targetNodes), 0, 0);
  var rangeStart = sourcePos !== null ? sourcePos : selection.from;
  tr.replaceRange(rangeStart, rangeStart + sourceNode.nodeSize, slice);
  return tr;
};
var getFormattedNode = exports.getFormattedNode = function getFormattedNode(tr) {
  var selection = tr.selection;
  var nodes = tr.doc.type.schema.nodes;

  // gating behind platform_editor_small_font_size to support task lists with font size applied,
  // but keep this solution general
  var isBlockTaskItemEnabled = !!nodes.blockTaskItem && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true);

  // Find the node to format from the current selection
  var nodeToFormat;
  var nodePos = selection.from;

  // Try to find the current node from selection
  var selectedNode = (0, _utils.findSelectedNodeOfType)([nodes.paragraph, nodes.heading, nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.layoutSection])(selection);
  if (selectedNode) {
    nodeToFormat = selectedNode.node;
    nodePos = selectedNode.pos;
  } else {
    // Try to find parent node (including list parents)
    var parentNodeTypes = [nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection];
    if (isBlockTaskItemEnabled) {
      parentNodeTypes.push(nodes.blockTaskItem);
    }
    var parentNode = (0, _utils.findParentNodeOfType)(parentNodeTypes)(selection);
    if (parentNode) {
      nodeToFormat = parentNode.node;
      nodePos = parentNode.pos;
      var paragraphOrHeadingNode = (0, _utils.findParentNodeOfType)([nodes.paragraph, nodes.heading])(selection);
      // Special case: if we found a listItem/taskItem/blockTaskItem, check if we need the parent list instead
      if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem || isBlockTaskItemEnabled && parentNode.node.type === nodes.blockTaskItem) {
        var listParent = (0, _utils.findParentNodeOfType)([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
        if (listParent) {
          // For list transformations, we want the list parent, not the listItem
          nodeToFormat = listParent.node;
          nodePos = listParent.pos;
        }
      } else if (parentNode.node.type !== nodes.blockquote && paragraphOrHeadingNode) {
        nodeToFormat = paragraphOrHeadingNode.node;
        nodePos = paragraphOrHeadingNode.pos;
      }
    }
  }
  if (!nodeToFormat) {
    nodeToFormat = selection.$from.node();
    nodePos = selection.$from.pos;
  }
  return {
    node: nodeToFormat,
    pos: nodePos
  };
};

/**
 * Ensures every `listItem` in a slice starts with a paragraph.
 *
 * @param slice - The slice to transform
 * @param schema - The editor schema, used to create new paragraph nodes
 * @returns A new slice with the transformation applied
 */
var transformSliceEnsureListItemParagraphFirst = exports.transformSliceEnsureListItemParagraphFirst = function transformSliceEnsureListItemParagraphFirst(slice, schema) {
  var _schema$nodes3 = schema.nodes,
    listItem = _schema$nodes3.listItem,
    paragraph = _schema$nodes3.paragraph;
  if (!listItem || !paragraph) {
    return slice;
  }
  return (0, _slice2.mapSlice)(slice, function (node) {
    if (node.type === listItem) {
      var firstChild = node.firstChild;
      if (firstChild && firstChild.type !== paragraph) {
        var emptyParagraph = paragraph.createAndFill();
        if (emptyParagraph) {
          var children = [emptyParagraph];
          for (var i = 0; i < node.childCount; i++) {
            children.push(node.child(i));
          }
          return node.copy(_model.Fragment.from(children));
        }
      }
    }
    return node;
  });
};