// Basic obfuscation-resistant normalization for the word filter: lowercase,
// common leetspeak substitutions, and collapsing 3+ repeated characters
// ("sooooo" -> "so") to one. Deliberately simple per the spec ("start simple,
// leave room to tighten later") — spaced-out letters ("b a d") and more exotic
// unicode lookalikes aren't handled yet.
const SUBS = { 4: 'a', '@': 'a', 3: 'e', 1: 'i', '!': 'i', 0: 'o', $: 's', 5: 's', 7: 't' }
const SUB_CHARS = /[4@31!05$7]/g

function normalize(text) {
  return text
    .toLowerCase()
    .replace(SUB_CHARS, (ch) => SUBS[ch] || ch)
    .replace(/(.)\1{2,}/g, '$1')
}

function escapeRegex(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

// Word-boundary match against already-normalized text. `word` is normalized
// here too, so callers can pass the raw stored value.
function matches(normalizedText, word) {
  const pattern = new RegExp(`\\b${escapeRegex(normalize(word))}\\b`, 'i')
  return pattern.test(normalizedText)
}

// Returns the first matching filter_words row ({word, severity}) or null.
function findMatch(content, words) {
  const normalizedText = normalize(content)
  return words.find((w) => matches(normalizedText, w.word)) || null
}

module.exports = { normalize, matches, findMatch }
