import {RegExpUtils, DOMUtils} from 'nylas-exports';

function _matchesAnyRegexp(text, regexps) {
  for (const excludeRegexp of regexps) {
    if (excludeRegexp.test(text)) {
      return true;
    }
  }
  return false;
}

function _runOnTextNode(node, matchers) {
  if (node.parentElement) {
    const withinScript = node.parentElement.tagName === "SCRIPT";
    const withinStyle = node.parentElement.tagName === "STYLE";
    const withinA = (node.parentElement.closest('a') !== null);
    if (withinScript || withinA || withinStyle) {
      return;
    }
  }
  if (node.textContent.trim().length < 4) {
    return;
  }

  let longest = null;
  let longestLength = null;
  for (const [prefix, regex, options = {}] of matchers) {
    regex.lastIndex = 0;
    const match = regex.exec(node.textContent);
    if (match !== null) {
      if (options.exclude && _matchesAnyRegexp(match[0], options.exclude)) {
        continue;
      }
      if (match[0].length > longestLength) {
        longest = [prefix, match];
        longestLength = match[0].length;
      }
    }
  }

  if (longest) {
    const [prefix, match] = longest;
    const href = `${prefix}${match[0]}`;
    const range = document.createRange();
    range.setStart(node, match.index);
    range.setEnd(node, match.index + match[0].length);
    const aTag = DOMUtils.wrap(range, 'A');
    aTag.href = href;
    aTag.title = href;
    return;
  }
}

export function autolink(doc, {async} = {}) {
  // Traverse the new DOM tree and make things that look like links clickable,
  // and ensure anything with an href has a title attribute.
  const textWalker = document.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT);
  const matchers = [
    ['mailto:', RegExpUtils.emailRegex(), {
      // Technically, gmail.com/bengotow@gmail.com is an email address. After
      // matching, manully exclude any email that follows the .*[/?].*@ pattern.
      exclude: [/\..*[/|?].*@/],
    }],
    ['tel:', RegExpUtils.phoneRegex()],
    ['', RegExpUtils.nylasCommandRegex()],
    ['', RegExpUtils.urlRegex({matchEntireString: false})],
  ];

  if (async) {
    const fn = (deadline) => {
      while (textWalker.nextNode()) {
        _runOnTextNode(textWalker.currentNode, matchers);
        if (deadline.timeRemaining() <= 0) {
          window.requestIdleCallback(fn, {timeout: 500});
          return;
        }
      }
    };
    window.requestIdleCallback(fn, {timeout: 500});
  } else {
    while (textWalker.nextNode()) {
      _runOnTextNode(textWalker.currentNode, matchers);
    }
  }

  // Traverse the new DOM tree and make sure everything with an href has a title.
  const aTagWalker = document.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT, {
    acceptNode: (node) =>
      (node.href ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP)
    ,
  });
  while (aTagWalker.nextNode()) {
    aTagWalker.currentNode.title = aTagWalker.currentNode.getAttribute('href');
  }
}
