/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

import visit from 'unist-util-visit';
export var DEFAULT_OPTIONS = {
  allowRelative: true,
  allowDocumentRelative: false,
  allowProtocols: ['https:', 'http:', 'mailto:']
};
export function euiMarkdownLinkValidator(_ref) {
  var _ref$allowRelative = _ref.allowRelative,
    allowRelative = _ref$allowRelative === void 0 ? DEFAULT_OPTIONS.allowRelative : _ref$allowRelative,
    _ref$allowDocumentRel = _ref.allowDocumentRelative,
    allowDocumentRelative = _ref$allowDocumentRel === void 0 ? DEFAULT_OPTIONS.allowDocumentRelative : _ref$allowDocumentRel,
    _ref$allowProtocols = _ref.allowProtocols,
    allowProtocols = _ref$allowProtocols === void 0 ? DEFAULT_OPTIONS.allowProtocols : _ref$allowProtocols,
    baseUrl = _ref.baseUrl;
  return function (ast) {
    visit(ast, 'link', function (_node) {
      var node = _node;
      if (allowRelative && allowDocumentRelative && (
      // Prevent throwing in non-browser environments if baseUrl isn't configured
      typeof window !== 'undefined' || baseUrl) && node.url && isDocumentRelativeUrl(node.url)) {
        var newUrl = resolveDocumentRelativeUrl(node.url, baseUrl !== null && baseUrl !== void 0 ? baseUrl : window.location.href);
        if (newUrl) {
          node.url = newUrl;
        } else {
          mutateLinkToText(node);
        }
      } else if (!validateUrl(node.url, {
        allowRelative: allowRelative,
        allowProtocols: allowProtocols
      })) {
        mutateLinkToText(node);
      }
    });
  };
}
export function mutateLinkToText(node) {
  var _node$children, _node$url;
  // this is an upsupported url, convert to a text node
  node.type = 'text';

  // and, if the link text matches the url there's only one value to show
  // otherwise render as the markdown syntax so both text & url remain, unlinked
  var linkText = ((_node$children = node.children) === null || _node$children === void 0 || (_node$children = _node$children[0]) === null || _node$children === void 0 ? void 0 : _node$children.value) || '';
  var linkUrl = (_node$url = node.url) !== null && _node$url !== void 0 ? _node$url : '';
  if (linkText === linkUrl) {
    node.value = linkText;
  } else {
    node.value = "[".concat(linkText, "](").concat(node.url, ")");
  }
  delete node.children;
  delete node.title;
  delete node.url;
  return node;
}
export function validateUrl(url, _ref2) {
  var _ref2$allowRelative = _ref2.allowRelative,
    allowRelative = _ref2$allowRelative === void 0 ? DEFAULT_OPTIONS.allowRelative : _ref2$allowRelative,
    _ref2$allowProtocols = _ref2.allowProtocols,
    allowProtocols = _ref2$allowProtocols === void 0 ? DEFAULT_OPTIONS.allowProtocols : _ref2$allowProtocols;
  // relative captures both relative paths `/` and protocols `//`
  var isRelative = url.startsWith('/');
  if (isRelative) {
    return allowRelative;
  }
  try {
    var parsedUrl = new URL(url);
    return allowProtocols.indexOf(parsedUrl.protocol) !== -1;
  } catch (e) {
    // failed to parse input as url
    return false;
  }
}

/**
 * Tests whether a URL is a document relative URL (e.g. "discover", "dashboards#/view/123")
 * that has no scheme, no leading slash, and is not an anchor or query-only link.
 */
export function isDocumentRelativeUrl(url) {
  if (url.startsWith('/') || url.startsWith('#') || url.startsWith('?')) {
    return false;
  }
  // Return false if the url starts with a protocol/scheme. Catches http:, https:, mailto:, etc.
  if (/^[a-z][a-z0-9+.-]*:/i.test(url)) {
    return false;
  }
  return true;
}

/**
 * Resolves a document relative URL against a base URL. This mostly replicates
 * native browser resolution of e.g. `<a href="discover">`, except that
 * trailing slashes are always removed to ensure consistent resolution,
 * regardless of whether the current page URL ends with a trailing slash or not.
 * Without this, "baz" on "/foo/bar/" resolves to "/foo/bar/baz" instead of the
 * expected "/foo/baz".
 */
function resolveDocumentRelativeUrl(url, baseUrl) {
  var normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
  try {
    var resolved = new URL(url, normalizedBase);
    return "".concat(resolved.pathname).concat(resolved.search).concat(resolved.hash);
  } catch (e) {
    // failed to parse URL
    return null;
  }
}