import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import ts from 'typescript'

const sourceUrl = new URL(
  '../src/views/Editor/EnglishSpeaking/composables/articleAutoFormatRules.ts',
  import.meta.url,
)
const compiled = ts.transpileModule(await readFile(sourceUrl, 'utf8'), {
  compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 },
}).outputText
const {
  countWords,
  normalizeParagraphs,
  hasOverlongParagraph,
  shouldPromptOnPaste,
  MAX_PARAGRAPH_WORDS,
  PASTE_PROMPT_MIN_WORDS,
} = await import(`data:text/javascript,${encodeURIComponent(compiled)}`)

/** 生成 n 个单词的文本 */
const words = n => Array.from({ length: n }, (_, i) => `w${i}`).join(' ')

// ---------------- countWords ----------------
assert.equal(countWords(''), 0)
assert.equal(countWords('   \n\n  '), 0)
assert.equal(countWords('one two   three'), 3)
assert.equal(countWords('  leading and trailing  '), 3)
assert.equal(countWords(words(300)), 300)

// ---------------- normalizeParagraphs ----------------
// 与后端 split_paragraphs 同规则：单 \n 与空行皆为段界
assert.equal(normalizeParagraphs('A one.\n\nB two.'), 'A one.\n\nB two.')
assert.equal(normalizeParagraphs('A one.\nB two.'), 'A one.\n\nB two.')
assert.equal(normalizeParagraphs('A one.\n\n\n\n   \nB two.'), 'A one.\n\nB two.')
assert.equal(normalizeParagraphs('  A   one    here.  '), 'A one here.')
assert.equal(normalizeParagraphs(''), '')
assert.equal(normalizeParagraphs('   \n\n  '), '')
// 幂等：归一化结果再归一化不变（会回写 textarea，必须稳定）
assert.equal(normalizeParagraphs(normalizeParagraphs('A.\nB.\n\n\nC.')), 'A.\n\nB.\n\nC.')

// ---------------- hasOverlongParagraph（299 / 300 / 301 边界）----------------
assert.equal(MAX_PARAGRAPH_WORDS, 300)
assert.equal(hasOverlongParagraph(''), false)
assert.equal(hasOverlongParagraph(words(299)), false)
assert.equal(hasOverlongParagraph(words(300)), false)
assert.equal(hasOverlongParagraph(words(301)), true)
// 多段：只要有一段超标就 true
assert.equal(hasOverlongParagraph(`${words(10)}\n\n${words(301)}`), true)
assert.equal(hasOverlongParagraph(`${words(200)}\n\n${words(200)}`), false)
// 单 \n 也是段界，故 200+200 不算一段 400
assert.equal(hasOverlongParagraph(`${words(200)}\n${words(200)}`), false)

// ---------------- shouldPromptOnPaste ----------------
assert.equal(PASTE_PROMPT_MIN_WORDS, 50)
// spec §3.2 step 1 只有两条：原内容 trim 后为空，且新内容 > 50 词。
assert.equal(shouldPromptOnPaste('', words(60)), true)       // 空框粘贴长文 → 弹
assert.equal(shouldPromptOnPaste('   ', words(51)), true)    // 纯空白算空框；51 词过阈值
assert.equal(shouldPromptOnPaste('\n\n  \n', words(60)), true) // 只剩换行的框同样算空
assert.equal(shouldPromptOnPaste('', words(50)), false)      // 恰好 50 词不弹（严格 >）
assert.equal(shouldPromptOnPaste('', words(40)), false)      // 短文不弹
assert.equal(shouldPromptOnPaste(words(300), words(400)), false) // 原文非空 → 不打断编辑
assert.equal(shouldPromptOnPaste('x', words(400)), false)    // 哪怕只有一个字符也不算空框
// 粘贴内容自带空行照样提示：带 \n\n ≠ 分得适合朗读（三段各 400 词就是反例）
assert.equal(shouldPromptOnPaste('', `${words(30)}\n\n${words(30)}`), true)
assert.equal(shouldPromptOnPaste('', `${words(400)}\n\n${words(400)}`), true)
// enspeak 的 sentenceCount>=2 条件已弃用：无标点长文照样提示
assert.equal(shouldPromptOnPaste('', words(60).replace(/\./g, '')), true)

console.log('article auto-format rules OK')
