/**
 * Плейсхолдеры текста заставки. Список — зеркало серверного (BumperPlaceholders.Tokens): сервер
 * отвергает незнакомые при сохранении, редактор подсказывает знакомые и показывает подстановку.
 *
 * Образцы нужны и палитре, и живому предпросмотру: без них поле «ДАЛЕЕ В {next.time}» выглядит
 * как строка кода, а не как кадр.
 */
export type PlaceholderSample = {
  token: string
  sample: string
}

export const PLACEHOLDERS: PlaceholderSample[] = [
  { token: 'channel', sample: 'Первый' },
  { token: 'channel.number', sample: '4' },
  { token: 'now.title', sample: 'Симпсоны' },
  { token: 'next.title', sample: 'Терминатор 2' },
  { token: 'now.episode', sample: 'с5э12' },
  { token: 'next.episode', sample: 'с1э3' },
  { token: 'next.year', sample: '1991' },
  { token: 'next.genre', sample: 'Боевик' },
  { token: 'next.time', sample: '21:30' },
  { token: 'tonight.title', sample: 'Терминатор 2' },
  { token: 'tonight.time', sample: '20:00' },
  { token: 'tomorrow.title', sample: 'Чужие' },
  { token: 'tomorrow.time', sample: '20:00' },
  { token: 'time', sample: '21:24' },
  { token: 'date', sample: '6 апреля' },
  { token: 'weekday', sample: 'понедельник' },
  { token: 'slot', sample: 'Вечернее кино' },
]

/** Плейсхолдеры момента показа: с ними каждый показ уникален и кэш рендера перестаёт работать. */
export const VOLATILE_TOKENS = new Set(['time', 'date', 'weekday'])

const TOKEN_PATTERN = /\{([a-zA-Z][a-zA-Z.]*)\}/g

const SAMPLES = new Map(PLACEHOLDERS.map((p) => [p.token, p.sample]))

/**
 * Как строка будет выглядеть в кадре. Зеркало серверного `BumperPlaceholders.Resolve`: пустые
 * значения схлопываются вместе с осиротевшими разделителями, а строка, где не подставился ни один
 * плейсхолдер, исчезает целиком — «ДАЛЕЕ В» без времени это не подпись, а мусор в кадре.
 */
export function resolveSample(text: string) {
  let tokens = 0
  let filled = 0

  const resolved = text.replace(TOKEN_PATTERN, (_, token: string) => {
    tokens += 1
    const value = SAMPLES.get(token) ?? ''
    if (value) filled += 1
    return value
  })

  if (tokens > 0 && filled === 0) return ''

  return trimSeparators(resolved.replace(/[ \t]{2,}/g, ' ').trim()).trim()
}

/** Разделители, которые остаются висеть, когда подставлять оказалось нечего. */
const SEPARATORS = '—–-:·,;/'

/**
 * Снимает разделители по краям. Посимвольно, а не регуляркой: у выражения с двумя якорями и `+`
 * по обе стороны альтернативы катастрофический откат на длинных строках, а строк тут сотни.
 */
function trimSeparators(value: string) {
  let start = 0
  let end = value.length

  while (start < end && SEPARATORS.includes(value[start])) start += 1
  while (end > start && SEPARATORS.includes(value[end - 1])) end -= 1

  return value.slice(start, end)
}

/** Плейсхолдеры строки, которых нет в списке допустимых, — их сервер отвергнет при сохранении. */
export function unknownTokens(text: string) {
  return [...text.matchAll(TOKEN_PATTERN)].map((m) => m[1]).filter((token) => !SAMPLES.has(token))
}

export function hasVolatileToken(text: string) {
  return [...text.matchAll(TOKEN_PATTERN)].some((m) => VOLATILE_TOKENS.has(m[1]))
}
