type AnchorMatchGroups = {
  prefix: string;
  href: string;
  suffix: string;
};
type ImgMatchGroups = {
  prefix: string;
  src: string;
  suffix: string;
};

const A_URL_REGEX = /<a\b(?<prefix>[^>]*)\bhref="(?<href>\/[^"]*)"(?<suffix>[^>]*)>/gm;
const IMG_URL_REGEX = /<img\b(?<prefix>[^>]*)\bsrc="(?<src>\/[^"]*)"(?<suffix>[^>]*)>/gm;

/**
 * Finds any local URLs in HTML tags (a, img) and replaces them with the appropriate
 * fully qualified link.
 */
export function htmlToAbsoluteUrls(originalText: string, site: URL) {
  const replacements: { match: string; replace: string }[] = [];
  for (const match of originalText.matchAll(A_URL_REGEX)) {
    const groups = match.groups as AnchorMatchGroups | undefined;
    if (groups?.href === undefined || groups?.prefix === undefined || groups?.suffix === undefined) {
      throw new Error(`Cannot make absolute for invalid URL ${match[0]}`);
    }
    replacements.push({
      match: match[0],
      replace: `<a${groups.prefix}href="${new URL(groups.href, site)}"${groups.suffix}>`,
    });
  }
  for (const match of originalText.matchAll(IMG_URL_REGEX)) {
    const groups = match.groups as ImgMatchGroups | undefined;
    if (groups?.src === undefined || groups?.prefix === undefined || groups?.suffix === undefined) {
      throw new Error(`Cannot make absolute for invalid URL ${match[0]}`);
    }
    replacements.push({
      match: match[0],
      replace: `<img${groups.prefix}src="${new URL(groups.src, site)}"${groups.suffix}>`,
    });
  }
  let newText = originalText;
  replacements.forEach(({ match, replace }) => {
    newText = newText.replace(match, replace);
  });
  return newText;
}
