// Wordlist 解析 + 抽词。纯函数，可单测。

export interface Word {
  difficulty: 'easy' | 'medium' | 'hard'
  english: string
  chinese: string
}

export interface Rng {
  next(): number
}
export const defaultRng: Rng = { next: () => Math.random() }

/** 解析一行 "easy - run - 跑"。空行或格式错误返回 null。 */
export function parseWordlistLine(line: string): Word | null {
  const s = line.trim()
  if (!s) return null
  const parts = s.split(' - ').map((p) => p.trim())
  if (parts.length !== 3) return null
  const [difficulty, english, chinese] = parts
  if (difficulty !== 'easy' && difficulty !== 'medium' && difficulty !== 'hard') return null
  if (!english || !chinese) return null
  return { difficulty, english, chinese }
}

/** 解析一整个 wordlist 文件文本。跳过空行 / 格式错误行。 */
export function parseWordlist(text: string): Word[] {
  return text.split(/\r?\n/).map(parseWordlistLine).filter((w): w is Word => w !== null)
}

/** difficulty 数字 → 包含的难度等级。 */
export function difficultyLevels(d: 1 | 2 | 3): Word['difficulty'][] {
  if (d === 1) return ['easy']
  if (d === 2) return ['easy', 'medium']
  return ['easy', 'medium', 'hard']
}

function wordKey(w: Word): string {
  return `${w.english}|${w.chinese}`
}

function shuffle<T>(arr: T[], rng: Rng): T[] {
  const a = [...arr]
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(rng.next() * (i + 1))
    ;[a[i], a[j]] = [a[j], a[i]]
  }
  return a
}

/**
 * 从 pool 抽 count 个词，优先未见过的。
 * 如果未见过的不够，用见过的补足，避免凑不齐。
 */
export function pickWords(
  pool: Word[],
  difficulty: 1 | 2 | 3,
  count: number,
  seen: Set<string>,
  rng: Rng = defaultRng,
): Word[] {
  const levels = new Set(difficultyLevels(difficulty))
  const filtered = pool.filter((w) => levels.has(w.difficulty))
  const unseen = filtered.filter((w) => !seen.has(wordKey(w)))
  const seenShuffled = shuffle(
    filtered.filter((w) => seen.has(wordKey(w))),
    rng,
  )
  const unseenShuffled = shuffle(unseen, rng)

  const picked: Word[] = []
  for (const w of unseenShuffled) {
    if (picked.length >= count) break
    picked.push(w)
  }
  for (const w of seenShuffled) {
    if (picked.length >= count) break
    picked.push(w)
  }
  return picked
}

export function wordKeyOf(w: Word): string {
  return wordKey(w)
}
