/**
 * 发音规则
 * 描述某一段文本的发音，供转换为 Ssml 的 <phoneme> 使用
 * @property content 原始文本内容（可为多字符，用于最长匹配）
 * @property alphabet 发音字母表，支持 'py'（拼音）或 'ipa'
 * @property ph 发音标记，依据 alphabet 的格式填写
 */
interface PronunciationRule {
  content: string
  alphabet: 'py' | 'ipa'
  ph: string
}

/**
 * 发音规则列表
 * 由多个发音规则构成的数组
 */
type PronunciationRuleList = Array<PronunciationRule>

/**
 * Ssml 转换器
 * 根据发音规则，将输入文本按最长匹配替换为 <phoneme> 并输出 Ssml
 */
class SsmlConverter {
  private readonly pronunciationRules: PronunciationRuleList

  /**
   * 创建 Ssml 转换器
   * @param pronunciationRules 多音字/词规则列表，按长度降序用于最长匹配
   */
  constructor(pronunciationRules: PronunciationRuleList) {
    this.pronunciationRules = [
      ...pronunciationRules.sort((a, b) => b.content.length - a.content.length),
    ]
  }

  /**
   * 批量转换段落为 Ssml 字符串数组
   * @param paragraphs 段落文本数组
   * @returns Ssml 字符串数组
   */
  convertParagraphs(paragraphs: string[]): string[] {
    const ssmlList: string[] = []
    for (const paragraph of paragraphs) {
      ssmlList.push(this.convertParagraph(paragraph))
    }
    return ssmlList
  }

  /**
   * 单段落转换为 Ssml
   * @param paragraph 段落文本
   * @returns Ssml 字符串
   */
  private convertParagraph(paragraph: string): string {
    let ssmlText = ''
    let cursor = 0

    while (cursor < paragraph.length) {
      const matchedRule: PronunciationRule | null = this.pronunciationRules.find(rule =>
        paragraph.startsWith(rule.content, cursor),
      ) ?? null

      if (matchedRule !== null) {
        ssmlText += `<phoneme alphabet="${matchedRule.alphabet}" ph="${matchedRule.ph}">${matchedRule.content}</phoneme>`
        cursor += matchedRule.content.length
      }
      else {
        ssmlText += paragraph[cursor]
        cursor += 1
      }
    }

    return `<speak>${ssmlText}</speak>`
  }
}

let ssmlConverter: SsmlConverter | null = null
/**
 * 创建或复用 Ssml 转换器（单例）
 * @param pronunciationRules 发音规则列表
 * @returns SsmlConverter 实例（全局复用）
 */
function createSsmlConverter(pronunciationRules: PronunciationRuleList): SsmlConverter {
  if (ssmlConverter === null) {
    ssmlConverter = new SsmlConverter(pronunciationRules)
  }
  return ssmlConverter
}

export {
  createSsmlConverter,
}

export type {
  PronunciationRule,
  PronunciationRuleList,
  SsmlConverter,
}
