import type { DraftPlanScriptInput } from './input.types';
import {
  resolveAgeBranch,
  resolveSalutation,
  smartDateDisplay,
  missedFromReason,
  lookupKeyPoints,
  lookupReviewDuration,
} from './script-facts';

/**
 * Prompt 版本管理约定:
 *   - 格式 "{callKey}@{date}-{letter}"
 *   - 改 prompt 文本 / system 指令 → 必须 bump letter(a→b→c...)
 *   - 改 schema 字段 → 必须 bump date(影响输入输出形态)
 *   - bump 后,AgentInvocation.promptVersion 字段会落新版本,
 *     SQL: `SELECT prompt_version, avg(judge_score), avg(cost_yuan) FROM agent_invocations
 *          WHERE call_key='draft_plan_script' GROUP BY prompt_version ORDER BY started_at DESC`
 *     即可对比版本效果。
 *
 * ⭐ 现行 promptVersion 常量在 call.ts。system prompt 由 skill-composer 装配
 *   (base-system.md + 命中的 SKILL.md),本文件只负责 user prompt(按患者拼事实)。
 *
 * 历史:
 *   - 2026-05-17-a — 初版,5 字段
 *   - 2026-05-24-b/c/d — B 方案 4 段 markdown + 事实漂移修
 *   - 2026-05-27-skills-base-v1 — 引入 base + skills harness,删除单块 legacy system
 *   - 2026-06-02-4module-v3 (现行) — 4 模块重构 + 确定性事实注入 + 单一聚焦
 */

/**
 * 业务 prompt — 装配 input 成具体上下文。
 *
 * 设计:
 *   - 把患者信息以"病历摘要"风格组织,LLM 对自然语言上下文比对 JSON 上下文更稳
 *   - skills 正文已直接注入 system(composeSystem),user prompt 不再重列名字清单(冗余,已删)
 *   - 能程序算的事实(称呼/日期/主漏诊项/复查时长/风险优势)全在 script-facts.ts 算好,
 *     LLM 只润色,不做年龄分支/日期格式/优先级/查表等确定性判断
 */
export function buildDraftPlanScriptPrompt(input: DraftPlanScriptInput): string {
  const { patient, clinicName, plan, clinicalContext } = input;

  // 单一聚焦:只取 priorityScore 最高那条 reason;其他 reason 的内容**完全不进 prompt**(不泄漏其他项)。
  const top = [...plan.reasons].sort((a, b) => b.priorityScore - a.priorityScore)[0];

  // 程序算好的确定性事实(LLM 不做年龄分支/日期格式/优先级/查表/称呼)
  const now = new Date();
  const branch = resolveAgeBranch(patient.age);
  const salutation = resolveSalutation({ nameMasked: patient.nameMasked, gender: patient.gender, branch });
  const lastVisitDate =
    clinicalContext.daysSinceLastVisit != null
      ? new Date(now.getTime() - clinicalContext.daysSinceLastVisit * 86400_000)
      : null;
  // 项目相关:日期/主诉/医生优先取"该应治未治项那次诊断"的,而非泛泛"最近一次就诊"
  const projectDate = top?.triggerDate ? new Date(top.triggerDate) : lastVisitDate;
  const dateDisplay = smartDateDisplay(projectDate, now) ?? '上次';
  const chiefComplaint = top?.triggerChiefComplaint ?? clinicalContext.lastChiefComplaint ?? null;
  const missed = top ? missedFromReason(top) : { label: plan.primaryScenarioLabel, key: null };
  const kp = lookupKeyPoints(missed.key);
  const reviewDuration = lookupReviewDuration(missed.key);
  const doctor = top?.triggerDoctor ?? clinicalContext.primaryDoctorName ?? '您的主治医生';

  const riskLines = kp ? kp.risks.map((r) => `  - ${r}`).join('\n') : '  - (按常识温和提醒,不吓唬人)';
  const advLines = kp ? kp.advantages.map((a) => `  - ${a}`).join('\n') : '  - 趁现在早点处理会更省心';

  // 患者基本信息(只给话术用得到的:性别归一中文,年龄)
  const g = (patient.gender ?? '').trim().toUpperCase();
  const genderText = g === '男' || g === 'M' ? '男' : g === '女' || g === 'F' ? '女' : '';
  const basics = [patient.nameMasked, genderText, patient.age != null ? `${patient.age}岁` : '']
    .filter(Boolean)
    .join('，');
  // 语气线索(熟客 vs 新客 → tone 选择;不念出来)
  const toneHint =
    clinicalContext.completedTreatmentCount > 0
      ? '老客户(之前在本诊所看过),语气可更熟络温和'
      : '首诊/新客户,语气专业可信为主';

  // 自报家门:有登录客服名 → "我是X诊所的{岗位}{姓名}";无名 → 通用"客服"(不编名字)
  const selfIntro = input.agent?.name
    ? `我是${clinicName}的${input.agent.roleTitle}${input.agent.name}`
    : `我是${clinicName}的客服`;

  // ⚠️ user prompt 只给"模板占位需要的值";用法说明全在 system 提示词,这里不重复、不放内部元数据。
  return `# 本次回访患者信息(只能用以下事实,不要编造或推断额外信息)

## 开场用
- {智能称呼}:${salutation}
- {自报家门}:${selfIntro}
- {智能时间显示}:${dateDisplay}
- 那次主诉:${chiefComplaint ?? '无记录'}
- {最后一次就诊医生}:${doctor}

## 本次应治未治(只讲这一个)
- {应治未治项}:${missed.label}
- {风险要点}:
${riskLines}
- {治疗优势}:
${advLines}
- {复查时长}:${reviewDuration}

## 患者
- ${basics}

## 语气
- ${toneHint}`;
}
