function textNode(text) {
  const node = new commonmark.Node("text", undefined);
  node.literal = text;
  return node;
}

function linkNode(text, link) {
  const linkNode = new commonmark.Node("link", undefined);
  linkNode.destination = `#q=${encodeURIComponent(link)}`;
  linkNode.appendChild(textNode(text));
  return linkNode;
}

function splitMatches(text, regexp) {
  // Regexp must be sticky.
  regexp = new RegExp(regexp, "gm");

  let i = 0;
  const result = [];

  let match = regexp.exec(text);
  while (match) {
    const matchText = match[0];

    if (match.index > i) {
      result.push([text.substring(i, match.index), false]);
    }

    result.push([matchText, true]);
    i = match.index + matchText.length;

    match = regexp.exec(text);
  }

  if (i < text.length) {
    result.push([text.substring(i, text.length), false]);
  }

  return result;
}

const regex = new RegExp("(?<!\w)#[\\w-]+");

function split(textNodes) {
  const text = textNodes.map(n => n.literal).join("");
  const parts = splitMatches(text, regex);

  return parts.map(part => {
    if (part[1]) {
      return linkNode(part[0], part[0]);
    } else {
      return textNode(part[0]);
    }
  });
}

export function transform(parsed) {
  const walker = parsed.walker();
  let event;

  let nodes = [];
  while ((event = walker.next())) {
    const node = event.node;
    if (event.entering && node.type === "text") {
      nodes.push(node);
    } else {
      if (nodes.length > 0) {
        split(nodes)
          .reverse()
          .forEach(newNode => {
            nodes[0].insertAfter(newNode);
          });

        nodes.forEach(n => n.unlink());
        nodes = [];
      }
    }
  }

  if (nodes.length > 0) {
    split(nodes)
      .reverse()
      .forEach(newNode => {
        nodes[0].insertAfter(newNode);
      });
    nodes.forEach(n => n.unlink());
  }

  return parsed;
}