import type { ScriptContext } from '../draft-plan-script/shared/input.types';
import { buildRichFactBlock, buildDeepExtensions } from '../draft-plan-script/shared/fact-block';
import type { WecomPlanZ, WecomWriteZ } from './schema';

/**
 * 企微话术的 user prompt。
 *
 * ⭐ **事实块直接复用电话档那一份**(buildRichFactBlock + buildDeepExtensions)——
 *   患者是谁、哪颗牙、医生说了什么、上次什么时候来的…… 这些与"用电话还是企微说"完全无关。
 *   ⛔ 别复制一份改改:安全护栏(不报价/福利不得加码/高龄不主推种植)全在里面,
 *   复制出去之后改了一处另一处会悄悄留在旧版本,而漏了哪条要等客服发出去才发现。
 *
 * ⚠️ 差异全部集中在**任务段**(--- 之后):电话是"拆几段讲",企微是"排个顺序、写成一条消息"。
 */
function facts(ctx: ScriptContext): string {
  const ext = buildDeepExtensions(ctx);
  return ext ? `${buildRichFactBlock(ctx)}\n\n${ext}` : buildRichFactBlock(ctx);
}

/** 步骤1:要点规划 —— ⚠️ 排的是**顺序**,不是段落 */
export function buildWecomPlanPrompt(ctx: ScriptContext): string {
  return `${facts(ctx)}

---
# 你的任务(本步:排要点顺序,不写正文)
这条消息是**发到患者微信里**的,他会一口气读完。规划要讲哪几点、按什么顺序讲。

按"从果(目标)倒推到因"来排:先想清这条消息要达成的果(让患者明白该回来处理本次问题),
再倒推为达成它患者需要先被讲清什么,把要点排成层层递进的推进线。
后果要客观说清、但不吓唬不推销。要点 3-6 条。

⚠️ 你排的是**讲的先后**,**不是分段** —— 最终产出是一整段连贯文字,不会有小标题。
所以别按"开场/正文/结尾"这种结构去想,想的是"先说什么才能让下一句站得住"。`;
}

/** 步骤2:写 —— 一次性单块(+ repair:上一稿 + 逐条修正约束) */
export function buildWecomWritePrompt(input: {
  ctx: ScriptContext;
  plan: WecomPlanZ;
  prevDraft?: WecomWriteZ;
  repairIssues?: Array<{ section: string; problem: string; fix: string }>;
}): string {
  if (input.repairIssues?.length) {
    const prev = input.prevDraft?.markdown ?? '(上一稿缺失,按要点重写并满足下列修正)';
    const issues = input.repairIssues
      .map((it, i) => `${i + 1}. 【${it.section}】问题:${it.problem}\n   必须改成:${it.fix}`)
      .join('\n');
    return `${facts(input.ctx)}

---
# 本步任务:修订(不是重写)
上一稿没通过自检。**在上一稿基础上,严格逐条改掉下面每一处问题**,改完输出完整修订稿。

## 上一稿(待修订)
${prev}

## 必须修正的问题(逐条,缺一不可)
${issues}

## 修订铁律
- 上面每一条都必须改到位,**一条都不能漏**;改法以"必须改成"为准。
- **只动被点名的地方**,其余句子保持原样,不要顺手重写或新增事实。
- 修正不得引入新的违规:不报价/不承诺疗效/≤18 岁不提拍片。
- ⛔ **不许出现任何时间占位符**(【时间段1】等),也不要自己编具体时间 ——
  这条消息是整段复制直发的,占位会原样发给患者。约时间用不含具体时间的邀约。
- 仍然是**一整块可直接发送的消息**,不许出现小标题或分段编号。`;
  }

  const outline = input.plan.points.map((p, i) => `${i + 1}. ${p.point}(${p.why})`).join('\n');
  return `${facts(input.ctx)}

---
# 本步要点顺序(按它写成一条消息,可微调措辞,不要新增事实)
${outline}

# 写的时候保持
- **一条能直接发出去的微信消息**:复制粘贴即可发送,不用再删改。
- **层层递进**:顺着要点推进,句与句承上启下,别并列罗列或跳跃。
- **后果说清但有分寸**:不处理的后果客观讲明(结合病历 + 牙科常识),让患者理解严重性;
  但**不夸大、不吓唬**(别下"会掉光""很危险"式结论)、**不推销促单报价**。`;
}

/** 步骤3:独立对抗校验 —— 新开上下文,默认怀疑 */
export function buildWecomVerifyPrompt(input: { ctx: ScriptContext; draft: WecomWriteZ }): string {
  return `${facts(input.ctx)}

---
# 你的任务(本步:对抗校验,不改写)
逐句核对下面这条**准备发给患者微信**的消息:
1. **接地**:每个说法能否追到上面"本次回访患者信息"里的事实?追不到 = 编造 → 记 issue。
2. **安全**:有无报价/费用、疗效承诺、≤18 提拍片?有 = 越界 → 记 issue。
   ⛔ 出现**任何时间占位符**(【时间段1】等)或自己编的具体时间("周三上午")= 记 issue ——
   这条消息整段复制直发,占位会原样发到患者微信里。
3. **逻辑与分寸**:围绕"让患者明白该回来处理"展开、层层递进、该说的没缺(点了问题要说后果、说了后果要给出路);
   有没有**吓唬/制造恐慌**或**推销/促单/施压**口吻?任一不到位 → 记 issue。
4. **患者听得懂**:有无诊断代码(如 K08)、英文/内部枚举、生硬术语,或含糊其辞(没说清哪颗牙)?有 = 记 issue。
5. ⭐ **可直接发送**(企微专有,电话档没有这一条):
   - 有没有**小标题 / 分段编号 / "第一第二" / \`##\`**?企微是一条消息,出现这些 = 记 issue;
   - 有没有**给客服自己看的话**混进正文(如"以下话术供参考""建议这样说")?= 记 issue;
   - ⛔ 除自报家门的 \`【回访客服】\` 外,**残留任何 \`【】\` 占位或内部标签** = 记 issue。
①②③④⑤ 全部通过 → pass=true、issues 空;任一不过 → pass=false 并逐条列出(位置、问题、修法)。

## 待校验消息
${input.draft.markdown}`;
}
