import { traverse } from '@atlaskit/adf-utils/traverse';
import { UNSUPPORTED_CONTENT_LEVEL_SEVERITY } from './UNSUPPORTED_CONTENT_LEVEL_SEVERITY';
import { UNSUPPORTED_CONTENT_LEVEL_SEVERITY_THRESHOLD_DEFAULTS } from './UNSUPPORTED_CONTENT_LEVEL_SEVERITY_THRESHOLD_DEFAULTS';
var buildUnsupportedContentLevelThresholds = function buildUnsupportedContentLevelThresholds(customThresholds) {
  return {
    degraded: (customThresholds === null || customThresholds === void 0 ? void 0 : customThresholds.degraded) || UNSUPPORTED_CONTENT_LEVEL_SEVERITY_THRESHOLD_DEFAULTS.DEGRADED,
    blocking: (customThresholds === null || customThresholds === void 0 ? void 0 : customThresholds.blocking) || UNSUPPORTED_CONTENT_LEVEL_SEVERITY_THRESHOLD_DEFAULTS.BLOCKING
  };
};
var countSupportedUnsupportedNodes = function countSupportedUnsupportedNodes(validDocument) {
  var unsupportedNodes = 0;
  var supportedNodes = 0;
  var unsupportedNodeTypeCount = {};
  var unsupportedNodeTypes = ['unsupportedInline', 'unsupportedBlock', 'confluenceUnsupportedInline', 'confluenceUnsupportedBlock'];
  traverse(validDocument, {
    any: function any(node) {
      if (unsupportedNodeTypes.includes(node.type)) {
        var _node$attrs;
        var originalNode = (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.originalValue;
        if (originalNode) {
          // start an independent traversal for the purpose of counting
          // unsupported content nodes (with nested children contributing towards
          // that count)
          traverse(originalNode, {
            any: function any(unsupportedNode, parent) {
              var _parent$parent$node$t, _parent$parent, _unsupportedNode$type, _unsupportedNodeTypeC;
              unsupportedNodes++;

              // Count the types of unsupported nodes
              var parentType = (_parent$parent$node$t = (_parent$parent = parent.parent) === null || _parent$parent === void 0 || (_parent$parent = _parent$parent.node) === null || _parent$parent === void 0 ? void 0 : _parent$parent.type) !== null && _parent$parent$node$t !== void 0 ? _parent$parent$node$t : 'unknown';
              var type = "".concat(parentType, "/").concat((_unsupportedNode$type = unsupportedNode === null || unsupportedNode === void 0 ? void 0 : unsupportedNode.type) !== null && _unsupportedNode$type !== void 0 ? _unsupportedNode$type : 'unknown');
              unsupportedNodeTypeCount[type] = ((_unsupportedNodeTypeC = unsupportedNodeTypeCount === null || unsupportedNodeTypeCount === void 0 ? void 0 : unsupportedNodeTypeCount[type]) !== null && _unsupportedNodeTypeC !== void 0 ? _unsupportedNodeTypeC : 0) + 1;
            }
          });
        }
        // force the parent traversal (which is counting supported content nodes)
        // to skip traversal/counting of nested children of the unsupported nodes
        return false;
      } else {
        supportedNodes++;
      }
    }
  });
  return {
    unsupportedNodes: unsupportedNodes,
    supportedNodes: supportedNodes,
    unsupportedNodeTypeCount: unsupportedNodeTypeCount
  };
};
var mapUnsupportedContentLevelToSeverity = function mapUnsupportedContentLevelToSeverity(unsupportedContentLevelPercent, thresholds) {
  if (thresholds.degraded <= unsupportedContentLevelPercent && unsupportedContentLevelPercent < thresholds.blocking) {
    return UNSUPPORTED_CONTENT_LEVEL_SEVERITY.DEGRADED;
  }
  if (thresholds.blocking <= unsupportedContentLevelPercent) {
    return UNSUPPORTED_CONTENT_LEVEL_SEVERITY.BLOCKING;
  }
  return UNSUPPORTED_CONTENT_LEVEL_SEVERITY.NORMAL;
};

/**
 * When given a valid ADF document, this function will return an information
 * object about the level of unsupported content in the document including:
 *
 * - counts: an object with the unsupportedNodes count and supportedNodes count.
 * - percentage: the percentage of unsupported nodes in the document relative to the rest
 * of the document content
 * - severity: The percentage mapped to a string value. This string will be either
 * "normal", "degraded" or "blocking" based on the threshold rules. (For e.g. if
 * `customThresholds = { degraded: 10, blocking: 30 }`, then a document with 9%
 * unsupported content will map to "normal", a document with 14% unsupported content
 * will map to "degraded" and a document with 33% unsupported content will map to "blocking".)
 *
 * **Example usage**
 *
 * ```
 * const exampleAdf = { type: 'doc', version: 1, content: [...] };
 * const customThresholds = { degraded: 30, blocking: 50 };
 * const data = getUnsupportedContentLevelData(exampleAdf, customThresholds);
 *
 * console.log(data.severity); // "normal"
 * console.log(data.counts.percentage); // 28
 * console.log(data.counts.unsupportedNodes); // 50
 * console.log(data.counts.supportedNodes); // 129
 * ```
 *
 */
export var getUnsupportedContentLevelData = function getUnsupportedContentLevelData(validDocument, customThresholds) {
  var _countSupportedUnsupp = countSupportedUnsupportedNodes(validDocument),
    unsupportedNodes = _countSupportedUnsupp.unsupportedNodes,
    supportedNodes = _countSupportedUnsupp.supportedNodes,
    unsupportedNodeTypeCount = _countSupportedUnsupp.unsupportedNodeTypeCount;
  var thresholds = buildUnsupportedContentLevelThresholds(customThresholds);
  var percentage = Math.round(unsupportedNodes / (unsupportedNodes + supportedNodes) * 100);
  var severity = mapUnsupportedContentLevelToSeverity(percentage, thresholds);
  return {
    severity: severity,
    percentage: percentage,
    counts: {
      supportedNodes: supportedNodes,
      unsupportedNodes: unsupportedNodes,
      unsupportedNodeTypeCount: unsupportedNodeTypeCount
    }
  };
};
// eslint-disable-next-line @atlaskit/editor/no-re-export
export { UNSUPPORTED_CONTENT_LEVEL_SEVERITY } from './UNSUPPORTED_CONTENT_LEVEL_SEVERITY';
// eslint-disable-next-line @atlaskit/editor/no-re-export
export { UNSUPPORTED_CONTENT_LEVEL_SEVERITY_THRESHOLD_DEFAULTS } from './UNSUPPORTED_CONTENT_LEVEL_SEVERITY_THRESHOLD_DEFAULTS';