// https://github.com/vueuse/vueuse/blob/main/packages/.vitepress/theme/utils.ts

const RE_H3 = /^### (.*$)/gm
const RE_H2 = /^## (.*$)/gm
const RE_H1 = /^# (.*$)/gm
const RE_BLOCKQUOTE = /^> (.*$)/gm
const RE_BOLD = /\*\*(.*)\*\*/g
const RE_ITALIC = /\*(.*)\*/g
const RE_IMG = /!\[(.*?)\]\((.*?)\)/g
const RE_LINK = /\[(.*?)\]\((.*?)\)/g
const RE_CODE = /`(.*?)`/g
const RE_NEWLINE = /\n$/gm

/**
 * Protocols allowed in markdown links and images.
 * Blocks `javascript:`, `data:`, `vbscript:`, protocol-relative `//` URLs, etc.
 */
const SAFE_URL_RE = /^(?:https?:\/\/|\/(?!\/)|#|mailto:)/i

/**
 * Escape HTML special characters to prevent XSS attacks.
 * Only escapes characters that can open HTML tags or attributes.
 * `>` is intentionally preserved so that markdown blockquote syntax still works.
 */
function escapeHtml(str: string): string {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')
}

/**
 * Sanitize a URL: only allow safe protocols.
 * Returns empty string for dangerous URLs like `javascript:`, `data:`, etc.
 */
function sanitizeUrl(url: string): string {
  const trimmed = url.trim()
  if (!trimmed)
    return ''
  return SAFE_URL_RE.test(trimmed) ? trimmed : ''
}

export function renderMarkdown(markdownText = '') {
  const htmlText = escapeHtml(markdownText)
    .replace(RE_H3, '<h3>$1</h3>')
    .replace(RE_H2, '<h2>$1</h2>')
    .replace(RE_H1, '<h1>$1</h1>')
    .replace(RE_BLOCKQUOTE, '<blockquote>$1</blockquote>')
    .replace(RE_BOLD, '<b>$1</b>')
    .replace(RE_ITALIC, '<i>$1</i>')
    .replace(RE_IMG, (_, alt, src) => {
      const safeSrc = sanitizeUrl(src)
      return safeSrc ? `<img alt='${alt}' src='${safeSrc}' />` : alt
    })
    .replace(RE_LINK, (_, text, href) => {
      const safeHref = sanitizeUrl(href)
      return safeHref ? `<a href='${safeHref}'>${text}</a>` : text
    })
    .replace(RE_CODE, '<code>$1</code>')
    .replace(RE_NEWLINE, '<br />')

  return htmlText.trim()
}

const RE_ISSUE = /#(\d+)/g

/**
 * Replace #issue references in HTML text nodes only.
 *
 * Tokenizes the HTML into three kinds of segments:
 *   1. `<a ...>...</a>` — preserved verbatim (avoids nested anchors)
 *   2. any other tag (e.g. `<img alt='#1'/>`, `<code>`) — preserved verbatim
 *      so attributes like `alt` / `src` / `href` are never rewritten
 *   3. text outside tags — `#123` becomes `<a href='.../issues/123'>#123</a>`
 */
function replaceIssueRefs(html: string, repo: string): string {
  return html.replace(
    /(<a\s[^>]*>[\s\S]*?<\/a>)|(<[^>]+>)|([^<]+)/gi,
    (match, _anchor, _tag, text) => {
      if (text == null)
        return match // anchor block or single tag — leave untouched
      return text.replace(RE_ISSUE, `<a href='${repo}/issues/$1'>#$1</a>`)
    },
  )
}

export function renderCommitMessage(msg: string, repo: string) {
  const html = renderMarkdown(msg)
  if (!repo)
    return html
  return replaceIssueRefs(html, repo)
}
