"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.findFilepaths = exports.canLinkBeCreatedInRange = exports.LinkMatcher = exports.FILEPATH_REGEXP = exports.DONTLINKIFY_REGEXP = void 0;
exports.getLinkCreationAnalyticsEvent = getLinkCreationAnalyticsEvent;
exports.getLinkDomain = getLinkDomain;
exports.isFromCurrentDomain = isFromCurrentDomain;
exports.isLinkInMatches = void 0;
exports.linkifyContent = linkifyContent;
exports.normalizeUrl = normalizeUrl;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _adfSchema = require("@atlaskit/adf-schema");
var _enums = require("../analytics/types/enums");
var _shouldAutoLinkifyTld = require("./should-auto-linkify-tld");
var _slice = require("./slice");
// File has been copied to packages/editor/editor-plugin-ai/src/provider/markdown-transformer/utils/hyperlink.ts
// If changes are made to this file, please make the same update in the linked file.

/* eslint-disable require-unicode-regexp -- Omit `u` so emitDeclarationOnly build (pre-ES2015 lib) does not error TS1501; patterns are ASCII-only paths and $/{ prefix. */
// Regular expression for a windows filepath in the format <DRIVE LETTER>:\<folder name>\
// Ignored via go/ees005
var FILEPATH_REGEXP = exports.FILEPATH_REGEXP = /([a-zA-Z]:|\\)([^\/:*?<>"|]+\\)?([^\/:*?<>"| ]+(?=\s?))?/gim;

// Don't linkify if starts with $ or {
// Ignored via go/ees005
var DONTLINKIFY_REGEXP = exports.DONTLINKIFY_REGEXP = /^(\$|\{)/;
/* eslint-enable require-unicode-regexp */

/**
 * Instance of class LinkMatcher are used in autoformatting in place of Regex.
 * Hence it has been made similar to regex with an exec method.
 * Extending it directly from class Regex was introducing some issues, thus that has been avoided.
 */
var LinkMatcher = exports.LinkMatcher = /*#__PURE__*/function () {
  function LinkMatcher() {
    (0, _classCallCheck2.default)(this, LinkMatcher);
  }
  return (0, _createClass2.default)(LinkMatcher, null, [{
    key: "create",
    value: function create() {
      var LinkMatcherRegex = /*#__PURE__*/function () {
        function LinkMatcherRegex() {
          (0, _classCallCheck2.default)(this, LinkMatcherRegex);
        }
        return (0, _createClass2.default)(LinkMatcherRegex, [{
          key: "exec",
          value: function exec(str) {
            var stringsBySpace = str.slice(0, str.length - 1).split(' ');
            var lastStringBeforeSpace = stringsBySpace[stringsBySpace.length - 1];
            var isLastStringValid = lastStringBeforeSpace.length > 0;
            if (!str.endsWith(' ') || !isLastStringValid) {
              return null;
            }
            if (DONTLINKIFY_REGEXP.test(lastStringBeforeSpace)) {
              return null;
            }
            var links = _adfSchema.linkify.match(lastStringBeforeSpace);
            if (!links || links.length === 0) {
              return null;
            }
            var lastMatch = links[links.length - 1];
            var lastLink = links[links.length - 1];
            lastLink.input = str.substring(lastMatch.index);
            lastLink.length = lastLink.lastIndex - lastLink.index + 1;
            lastLink.index = str.lastIndexOf(lastStringBeforeSpace) + lastMatch.index;
            return lastLink;
          }
        }]);
      }();
      return new LinkMatcherRegex();
    }
  }]);
}();
/**
 * Adds protocol to url if needed.
 */
function normalizeUrl(url) {
  if (!url) {
    return '';
  }
  if ((0, _adfSchema.isSafeUrl)(url)) {
    return url;
  }
  return (0, _adfSchema.normalizeUrl)(url);
}

/**
 * Linkify content in a slice (eg. after a rich text paste)
 */
function linkifyContent(schema) {
  return function (slice) {
    return (0, _slice.mapSlice)(slice, function (node, parent) {
      var isAllowedInParent = !parent || parent.type !== schema.nodes.codeBlock;
      var link = node.type.schema.marks.link;
      if (link === undefined) {
        throw new Error('Link not in schema - unable to linkify content');
      }
      if (isAllowedInParent && node.isText && !link.isInSet(node.marks)) {
        var linkified = [];
        // Ignored via go/ees005
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        var text = node.text;
        var matches = findLinkMatches(text).filter(_shouldAutoLinkifyTld.shouldAutoLinkifyMatch);
        var pos = 0;
        var filepaths = findFilepaths(text);
        matches.forEach(function (match) {
          if (isLinkInMatches(match.index, filepaths)) {
            return;
          }
          if (match.index > 0) {
            linkified.push(node.cut(pos, match.index));
          }
          linkified.push(node.cut(match.index, match.lastIndex).mark(link.create({
            href: normalizeUrl(match.url)
          }).addToSet(node.marks)));
          pos = match.lastIndex;
        });
        if (pos < text.length) {
          linkified.push(node.cut(pos));
        }
        return linkified;
      }
      return node;
    });
  };
}

// eslint-disable-next-line jsdoc/require-jsdoc
function getLinkDomain(url) {
  // Remove protocol and www., if either exists
  // Ignored via go/ees005
  // eslint-disable-next-line require-unicode-regexp
  var withoutProtocol = url.toLowerCase().replace(/^(.*):\/\//, '');
  // Ignored via go/ees005
  // eslint-disable-next-line require-unicode-regexp
  var withoutWWW = withoutProtocol.replace(/^(www\.)/, '');

  // Remove port, fragment, path, query string
  // Ignored via go/ees005
  // eslint-disable-next-line require-unicode-regexp
  return withoutWWW.replace(/[:\/?#](.*)$/, '');
}

// eslint-disable-next-line jsdoc/require-jsdoc
function isFromCurrentDomain(url) {
  if (!window || !window.location) {
    return false;
  }
  var currentDomain = window.location.hostname;
  var linkDomain = getLinkDomain(url);
  return currentDomain === linkDomain;
}

/**
 * Fetch linkify matches from text
 * @param text Input text from a node
 * @returns Array of linkify matches. Returns empty array if text is empty or no matches found;
 */
function findLinkMatches(text) {
  if (text === '') {
    return [];
  }
  return _adfSchema.linkify.match(text) || [];
}
var findFilepaths = exports.findFilepaths = function findFilepaths(text) {
  var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
  // Creation of a copy of the RegExp is necessary as lastIndex is stored on it when we run .exec()
  // Ignored via go/ees005
  // eslint-disable-next-line require-unicode-regexp -- Ignored via go/ees005
  var localRegExp = new RegExp(FILEPATH_REGEXP);
  var match;
  var matchesList = [];
  var maxFilepathSize = 260;
  // Ignored via go/ees005
  // eslint-disable-next-line no-cond-assign
  while ((match = localRegExp.exec(text)) !== null) {
    var start = match.index + offset;
    var end = localRegExp.lastIndex + offset;
    if (end - start > maxFilepathSize) {
      end = start + maxFilepathSize;
    } // We don't care about big strings of text that are pretending to be filepaths!!
    matchesList.push({
      startIndex: start,
      endIndex: end
    });
  }
  return matchesList;
};
var isLinkInMatches = exports.isLinkInMatches = function isLinkInMatches(linkStart, matchesList) {
  for (var i = 0; i < matchesList.length; i++) {
    if (linkStart >= matchesList[i].startIndex && linkStart < matchesList[i].endIndex) {
      return true;
    }
  }
  return false;
};

// eslint-disable-next-line jsdoc/require-jsdoc
function getLinkCreationAnalyticsEvent(inputMethod, url) {
  return {
    action: _enums.ACTION.INSERTED,
    actionSubject: _enums.ACTION_SUBJECT.DOCUMENT,
    actionSubjectId: _enums.ACTION_SUBJECT_ID.LINK,
    attributes: {
      inputMethod: inputMethod,
      fromCurrentDomain: isFromCurrentDomain(url)
    },
    eventType: _enums.EVENT_TYPE.TRACK,
    nonPrivacySafeAttributes: {
      linkDomain: getLinkDomain(url)
    }
  };
}
var canLinkBeCreatedInRange = exports.canLinkBeCreatedInRange = function canLinkBeCreatedInRange(from, to) {
  return function (state) {
    if (!state.doc.rangeHasMark(from, to, state.schema.marks.link)) {
      var $from = state.doc.resolve(from);
      var $to = state.doc.resolve(to);
      var link = state.schema.marks.link;
      if ($from.parent === $to.parent && $from.parent.isTextblock) {
        if ($from.parent.type.allowsMarkType(link)) {
          var allowed = true;
          state.doc.nodesBetween(from, to, function (node) {
            var hasInlineCard = node.type === state.schema.nodes.inlineCard;
            allowed = allowed && !node.marks.some(function (m) {
              return m.type.excludes(link);
            }) && !hasInlineCard;
            return allowed;
          });
          return allowed;
        }
      }
    }
    return false;
  };
};