/**
 * Подготовка текста для TTS и распознавание команд сброса.
 * Порт satellite/text.py + satellite/llm.py (RESET_PATTERNS, FILLER_PATTERNS).
 *
 * Отличие от Python-версии: время «HH:MM» раскрывается в слова всегда в
 * именительном падеже (без pymorphy3). Звучит чуть менее естественно в
 * конструкциях вроде «встретимся в 14:30», но без зависимости от морфологии.
 */

const RESET_PATTERNS = new RegExp(
  '(начни|начать|создай|открой|давай).{0,10}(новую|новый|чистую|чистый).{0,10}' +
  '(сессию|сессия|диалог|разговор|чат)' +
  '|' +
  '(сбрось|очисти|обнови).{0,10}(сессию|диалог|разговор|чат|историю|контекст)',
  'i'
)

const FILLER_PATTERNS = new RegExp(
  '(?:(?:сейчас посмотрю|дай мне секунду|дай секунду|проверяю|загружаю|узнаю' +
  '|смотрю|одну секунду|я сейчас посмотрю|я проверю|попробую другой источник' +
  '|нужны конкретные числа|дай мне загрузить)[^.!?]*[.!?]?\\s*)+',
  'gi'
)

export function isResetCommand(text: string): boolean {
  return RESET_PATTERNS.test(text)
}

export function stripFillers(text: string): string {
  return text.replace(FILLER_PATTERNS, '').trim()
}

// ── числа в слова (рус, именительный, кардинальные 0..99) ─────────────
const ONES_M = ['', 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять']
const ONES_F = ['', 'одна', 'две', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять']
const TEENS = ['десять', 'одиннадцать', 'двенадцать', 'тринадцать', 'четырнадцать', 'пятнадцать',
               'шестнадцать', 'семнадцать', 'восемнадцать', 'девятнадцать']
const TENS = ['', '', 'двадцать', 'тридцать', 'сорок', 'пятьдесят', 'шестьдесят', 'семьдесят',
              'восемьдесят', 'девяносто']

function numToWords(n: number, gender: 'm' | 'f' = 'm'): string {
  if (n === 0) return 'ноль'
  if (n < 0 || n > 99) return String(n)
  const ones = gender === 'f' ? ONES_F : ONES_M
  if (n < 10) return ones[n]
  if (n < 20) return TEENS[n - 10]
  const t = Math.floor(n / 10)
  const o = n % 10
  return o === 0 ? TENS[t] : `${TENS[t]} ${ones[o]}`
}

function hoursWord(n: number): string {
  const last2 = n % 100
  const last1 = n % 10
  if (last2 >= 11 && last2 <= 14) return 'часов'
  if (last1 === 1) return 'час'
  if (last1 >= 2 && last1 <= 4) return 'часа'
  return 'часов'
}

function minutesWord(n: number): string {
  const last2 = n % 100
  const last1 = n % 10
  if (last2 >= 11 && last2 <= 14) return 'минут'
  if (last1 === 1) return 'минута'
  if (last1 >= 2 && last1 <= 4) return 'минуты'
  return 'минут'
}

function formatTime(h: number, mm: number): string {
  let out = `${numToWords(h, 'm')} ${hoursWord(h)}`
  if (mm > 0) out += ` ${numToWords(mm, 'f')} ${minutesWord(mm)}`
  return out
}

// ── единицы измерения со слэшем ───────────────────────────────────────
const UNIT_SLASH: Array<[RegExp, string]> = [
  [/\bкм\s*\/\s*ч\b/gi, 'километров в час'],
  [/\bм\s*\/\s*с\b/gi, 'метров в секунду'],
  [/\bкм\s*\/\s*с\b/gi, 'километров в секунду'],
  [/\bмб\s*\/\s*с\b/gi, 'мегабит в секунду'],
  [/\bгб\s*\/\s*с\b/gi, 'гигабит в секунду'],
  [/\bруб\s*\/\s*мес\b/gi, 'рублей в месяц'],
  [/\bр\s*\/\s*мес\b/gi, 'рублей в месяц'],
]

const ABBR: Array<[RegExp, string]> = [
  [/\bт\.\s*е\./gi, 'то есть'],
  [/\bт\.\s*к\./gi, 'так как'],
  [/\bт\.\s*д\./gi, 'так далее'],
  [/\bт\.\s*п\./gi, 'тому подобное'],
  [/\bи\s*т\.\s*д\./gi, 'и так далее'],
  [/\bи\s*т\.\s*п\./gi, 'и тому подобное'],
]

export function cleanForSpeech(input: string): string {
  let t = input
  // markdown — emojis: supplementary planes + symbols + dingbats + misc-symbols
  t = t.replace(/[\u{1F000}-\u{1FFFF}☀-➿]/gu, '')
  t = t.replace(/\*+/g, '')
  t = t.replace(/#+\s/g, '')
  t = t.replace(/^- /gm, '')
  t = t.replace(/\[.*?\]\(.*?\)/g, '')
  t = t.replace(/\n+/g, '. ')

  for (const [pat, repl] of UNIT_SLASH) t = t.replace(pat, repl)

  // знаки перед числом
  t = t.replace(/(^|\s)\+(\d)/g, '$1плюс $2')
  t = t.replace(/(^|\s)-(\d)/g, '$1минус $2')
  t = t.replace(/±(\d)/g, 'плюс-минус $1')

  // время HH:MM (опционально с предлогом — предлог сохраняем как есть, время в номинативе)
  t = t.replace(
    /(?:\b(с|со|до|от|после|около|к|ко|в|во|на|через|за|перед|между|о|об|при)\s+)?(\d{1,2}):(\d{2})\b/gi,
    (_m, prep: string | undefined, hStr: string, mmStr: string) => {
      const h = parseInt(hStr, 10)
      const mm = parseInt(mmStr, 10)
      if (h < 0 || h > 23 || mm < 0 || mm > 59) return _m
      const words = formatTime(h, mm)
      return prep ? `${prep} ${words}` : words
    }
  )

  // дроби и слэш
  t = t.replace(/(\d+)\s*\/\s*(\d+)/g, '$1 из $2')
  t = t.replace(/\//g, ' или ')

  // символы
  t = t.replace(/°\s*C\b/gi, ' градусов')
  t = t.replace(/°\s*F\b/gi, ' градусов Фаренгейта')
  t = t.replace(/°/g, ' градусов')
  t = t.replace(/%/g, ' процентов')
  t = t.replace(/№/g, ' номер ')
  t = t.replace(/&/g, ' и ')
  t = t.replace(/@/g, ' собака ')
  t = t.replace(/×/g, ' на ')

  for (const [pat, repl] of ABBR) t = t.replace(pat, repl)

  // схлопывание
  t = t.replace(/([:;,!?])\s*\./g, '$1')
  t = t.replace(/\.\s*\.+/g, '.')
  t = t.replace(/\s+/g, ' ')
  t = t.replace(/(\d+)\.(\s)/g, '$1$2')
  return t.trim()
}
