/**
 * HARDREGEX/SOFTREGEX rule values are authored as SAS PRX patterns, which
 * require the delimiter form `/pattern/flags` (prxparse's own syntax check
 * in mpe_validations_postedit.sas requires it). A bare pattern with no
 * delimiters is also accepted, for backwards compatibility with existing
 * rules/tests. Passing the delimited form as-is to `new RegExp(string)`
 * would treat the slashes and flags as literal pattern text instead of
 * stripping/applying them, so this parses the PRX form before constructing
 * the regex.
 *
 * PRX also accepts some Perl-only regex syntax with no direct JS equivalent.
 * Three mechanical, unambiguous cases are translated below - a leading
 * `(?i)` modifier, an escaped `\Q...\E` literal sequence, and `\A`/`\z`
 * absolute anchors.
 * Atomic groups (`(?>...)`) and possessive quantifiers (`a++`) are NOT
 * translated: both would need a lookahead+backreference rewrite that
 * changes the pattern's capture-group numbering, a real correctness risk
 * for comparatively rare constructs, so they're left to fail (they already
 * throw, which every caller already treats as "always valid" / "never
 * warn", same as any other malformed pattern).
 */
const escapeRegExpMetacharacters = (text: string): string =>
  text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')

export const parseRegexRule = (ruleValue: string): RegExp => {
  const delimited = /^\/(.*)\/([a-z]*)$/s.exec(ruleValue)

  if (!delimited) return new RegExp(ruleValue)

  let [, body, flags] = delimited

  const inlineCaseInsensitive = /^\(\?i\)/.exec(body)

  if (inlineCaseInsensitive) {
    body = body.slice(inlineCaseInsensitive[0].length)
    if (!flags.includes('i')) flags += 'i'
  }

  body = body.replace(/\\Q([\s\S]*?)\\E/g, (_match, literal) =>
    escapeRegExpMetacharacters(literal)
  )

  body = body.replace(/\\A/g, '^').replace(/\\z/g, '(?![\\s\\S])')

  return new RegExp(body, flags)
}
