/**
 * DraftPlanScript AiCall 的输入契约。
 *
 * harness 原则:input 只装 AiCall 真正用到的字段(渐进式披露),
 * 不要把全量 patient / persona 塞进来污染 context。
 *
 * 装配责任在 orchestrator,见 plan-script.orchestrator.ts。
 */

export interface DraftPlanScriptInput {
  /** 患者信息(已脱敏:nameMasked, phone 不传) */
  patient: {
    nameMasked: string;
    gender: string | null;
    age: number | null;
  };

  /** 诊所名(给 LLM 用作"我是X诊所的客服顾问",避免编造"XX口腔") */
  clinicName: string;

  /** Plan 信息 */
  plan: {
    /** 主场景 label(从 scenario 枚举翻译,如"治疗后复诊召回"/"漏治-缺失牙"等) */
    primaryScenarioLabel: string;
    /** ⭐ 主场景 raw key(skill composer.applies.scenario 用,如 'treatment_initiation_recall') */
    primaryScenarioKey: string | null;
    priorityScore: number;
    /** ⭐ 本次召回的明确目的(plan.goal 原文,如"邀约做牙周基础治疗(SRP/翻瓣),控制炎症发展")
     *  让 LLM followup 段对齐该目标,不再自己脑补"我们想约您来评估" */
    goal: string | null;
    /** 触发原因摘要(最多 3 条) */
    reasons: Array<{
      scenarioLabel: string;
      /** ⭐ 子场景 base key(去 @tooth 后缀,如 'caries_no_filling';skill composer 推 dxCode 用) */
      subKey: string | null;
      /** ⭐ ICD-10 K-code(K00-K09,skill composer.applies.diagnosisCodePrefix 用) */
      dxCode: string | null;
      reason: string;
      priorityScore: number;
      /** 触发该诊断/建议的医生(LLM 在 followup 段必须引用此人,不要用 primaryDoctorName)
       *  来源:reason.evidence.factIds[0] → patient_facts.content.doctor_name
       *  null = 该 fact 无医生记录 → LLM fallback "您的主诊医生" 泛指 */
      triggerDoctor: string | null;
      /** 触发诊断/建议的日期(YYYY-MM-DD),给 LLM 在话术里用,如"上次姜医生 X 月 X 日给您检查时...") */
      triggerDate: string | null;
    }>;
  };

  /** Persona 关键特征(只挑相关的,不全量) */
  personaHighlights: Array<{
    label: string;          // 中文 label,如"客户价值"
    description: string;    // 短描述,如"高价值(累计消费 ¥35,000)"
  }>;

  /** 临床事实摘要(只挑最近 / 跟召回相关的) */
  clinicalContext: {
    daysSinceLastVisit: number | null;
    lastVisitSummary: string | null;       // 上次到店做了什么(一句话)
    pendingTreatments: string[];           // 待做治疗(简短描述,牙位已转患者俗称,如"缺失牙(下门牙)")
    treatmentChainSummary: string | null;  // 治疗链当前阶段一句话
    /** 主诊医生名(从最近 treatment/diagnosis fact 抽);LLM 必须用此名,不可编造 */
    primaryDoctorName: string | null;
    /** ⭐ 正在进行的治疗链摘要(每条一句:"牙周治疗在管 · 上次龈上洁治 · 吴医生 · 2024.04.27")
     *  LLM 用于:① 不重复邀约已在管的治疗 ② 引用历史治疗显出"诊所记得 ta" */
    ongoingChains: string[];
    /** ⭐ 已做治疗总次数(信任锚);LLM 用于:老客可以更家常,新客需自报家门更详细 */
    completedTreatmentCount: number;
  };
}

/**
 * AiCall 输出契约(B 方案 · 2026-05-24 重写)。
 *
 * LLM 直接输出 4 段 Markdown 字符串 + tone tag。
 * orchestrator 把每段直接映射到前端 ScriptSection,**不再做模板拼接**;
 * 段内子结构(`**目的**:` / `**注意**` / `**异议预判**` / `**回写要点**` / `### A.` ...)
 * 由 LLM 按 schema.ts 的 .describe() 契约自己写。
 *
 * 为什么从"结构化字段+后端拼模板" 改成"LLM 直出 Markdown":
 *   - 段内子结构需求(目的/正文/注意)模板化后失去个性化,套话感重
 *   - 4 段独立 markdown 字段对 zod 仍是强校验(长度 + .describe() 格式契约)
 *   - 流式仍然可行(generateObject partial 阶段每段 string 逐字符流出)
 *   - Flash 模型友好 — schema 字段少,LLM 单字段长 markdown 比多字段嵌套对象更稳
 */
export interface DraftPlanScriptOutput {
  /** 整体语气标签(给客服参考) */
  tone: 'warm' | 'professional' | 'urgent';

  /** 开场段 markdown:**目的** + > 通话片段 + **注意** bullet */
  opening: string;

  /** 切入话题段 markdown:**目的** + 1-2 段 > 对话 + **异议预判** bullet */
  followup: string;

  /** 异议处理段 markdown:3-4 个 ### A./B./C./D. 子标题 + > 应对 */
  objection: string;

  /** 结束·信息确认段 markdown:> 确认话术 + **回写要点** bullet */
  close: string;
}
