/** Готовые шаблоны для частых раскладок имён. Подпись переводится в UI по ключу. */
export const REGEX_PRESETS: { key: string; pattern: string }[] = [
  { key: 'seriesWord', pattern: String.raw`[Сс]ерия\s*(\d{1,3})` },
  { key: 'episodeWord', pattern: String.raw`[Ээ]пизод\s*(\d{1,3})` },
  { key: 'seasonEpisode', pattern: String.raw`[Ss](\d{1,2})[Ee](\d{1,3})` },
  // Производственный код: «2ACV01». Две группы — из него читаются и сезон, и серия.
  { key: 'productionCode', pattern: String.raw`(\d{1,2})[A-Z]{1,4}(\d{2,3})` },
  { key: 'afterDash', pattern: String.raw`[-–—]\s*(\d{1,3})` },
  { key: 'firstNumber', pattern: String.raw`(?:^|\D)(\d{1,3})(?:\D|$)` },
]

/** Числа в имени файла: позиция и текст — по ним строится кликабельный образец. */
export function findNumbers(fileName: string): { index: number; start: number; text: string }[] {
  return [...fileName.matchAll(/\d+/g)].map((match, index) => ({
    index,
    start: match.index ?? 0,
    text: match[0],
  }))
}

const escapeRegex = (value: string) => value.replace(/[.*+?^${}()|[\]\\/-]/g, String.raw`\$&`)

const isLetter = (char: string) => /\p{L}/u.test(char)
const isLetterOrDigit = (char: string) => /[\p{L}\p{N}]/u.test(char)

/**
 * Хвост строки из символов, удовлетворяющих условию. Обходим с конца вручную, а не шаблоном вида
 * `X*$`: такой шаблон движок примеряет с каждой позиции строки и получает квадратичное время
 * (см. предупреждение анализатора о backtracking), тогда как здесь один линейный проход.
 */
function trailingRun(value: string, matches: (char: string) => boolean): string {
  let start = value.length
  while (start > 0 && matches(value[start - 1])) start--
  return value.slice(start)
}

/**
 * Строит regex по указанному пользователем числу в имени файла. Якорем берётся слово перед числом
 * («Серия 01» → `Серия\s*(\d{1,3})`): позиция числа в разных файлах гуляет, а слово рядом — нет.
 * Если перед числом только разделители — якорем становятся они, а число в начале имени крепится к `^`.
 */
export function buildEpisodeRegex(fileName: string, occurrenceIndex: number): string {
  const numbers = findNumbers(fileName)
  const target = numbers[occurrenceIndex]
  if (!target) return ''

  // Всегда до трёх цифр — как во встроенных шаблонах: правило строится по одному файлу,
  // а применяется ко всей папке, где рядом может лежать и «Серия 100».
  const digits = String.raw`(\d{1,3})`
  const before = fileName.slice(0, target.start)
  if (!before.trim()) return String.raw`^\s*${digits}`

  // Разделители между якорем и числом описываем классом, а не буквально: в соседних файлах
  // там встречается то пробел, то точка, то подчёркивание.
  const gap = trailingRun(before, (char) => !isLetterOrDigit(char))
  const anchorSource = before.slice(0, before.length - gap.length)
  // Якорь — только буквы: захвати он цифры, «S01E07» дало бы правило `S01E(\d)`, прибитое
  // к первому сезону, и на «S02E05» оно бы уже не сработало.
  const anchor = trailingRun(anchorSource, isLetter)

  const separator = gap ? String.raw`[\s._-]*` : ''
  if (anchor) return `${escapeRegex(anchor)}${separator}${digits}`

  // Слова перед числом нет — цепляемся за последний разделитель («- 05», «(05)»).
  const punctuation = gap.trim().slice(-1)
  return punctuation ? String.raw`${escapeRegex(punctuation)}\s*${digits}` : String.raw`\s${digits}`
}
