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

// ⭐ 话术上下文(tier-agnostic):稳健/标准/深度三档共用同一份 ScriptContext;
//   也被实时教练复用(realtime-coach-context)。脊柱 = AiCallRunner,策略 = 各档 AiCall。
//   设计见 docs/algorithm/ai-script-generation.md。
export interface ScriptContext {
  // 患者数据(ScriptContext = 三档全集数据,各档组装 user prompt 时各取所需;非审计快照)。
  //   ⚠️ ID 类不进(关联走 agent_invocations.linked_patient_id 列);真名 name 是数据,
  //   但**不进 user prompt**(走 token 回填),只供内部/深度档更个性化时取用。
  patient: {
    /** 患者真名(如"张震校")— 数据;不直出 user prompt,话术称呼走 salutation/token */
    name: string | null;
    /** 通话称呼(单一源:年龄+性别+监护人 aware)— 未成年=监护人称呼/家长,成人=先生/女士。原 nameMasked */
    salutation: string;
    gender: string | null;
    age: number | null;
    /** 病历号(host 病历主键,如 "FY0A000922")— 供客服核对身份,可空 */
    medicalRecordNumber?: string | null;
    /** 监护人(未成年触达对象)— 让话术知道"打给家长、患者是孩子(称宝宝)";成人/无监护人 → null */
    guardian?: { relationshipLabel: string; name: string | null } | null;
  };

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

  /** ⭐ 当前回访客服(自报家门用:岗位角色 + 姓名,如 客服主管/李莉)。
   *  来源:登录用户 JWT(role→患者侧称呼 + dictionary.users[sub]→姓名)。
   *  name 为空 → prompt 退回通用"客服",不编名字。 */
  agent?: { name: string | null; roleTitle: 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;
      /** ⭐ 项目相关:该诊断**那次接诊**的主诉(emr illness_desc 原文)。
       *  单一聚焦时优于"最近一次主诉"—— 缺牙是哪次来发现的、那次为什么来,更贴合本应治未治项。可空 */
      triggerChiefComplaint?: string | null;
    }>;
  };

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

  /** 临床事实摘要(只挑最近 / 跟召回相关的) */
  clinicalContext: {
    daysSinceLastVisit: number | null;
    lastVisitSummary: string | null;       // 上次到店做了什么(一句话)
    /** 上次就诊主诉(emr_record.illness_desc 原文,自由文本直喂 LLM 当上下文;可空) */
    lastChiefComplaint?: string | null;
    pendingTreatments: string[];           // 待做治疗(reason 派生,即"未启动治疗";牙位已转俗称)
    /** 主治医生名(从最近 treatment/diagnosis fact 抽);LLM 必须用此名,不可编造 */
    primaryDoctorName: string | null;
    /** ⭐ 近期做过的治疗(每条一句:"做过牙周 · 上次龈上洁治 · 吴医生 · 2024.04")
     *  来源 treatment_record(非治疗链);LLM 用于:① 不重复邀约已做过的 ② 引用历史显"诊所记得 ta"。
     *  ⚠️ 治疗链(chain-composer)已废弃 → 这里只读"做过什么治疗",不含链/阶段概念。 */
    recentTreatments: 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 比多字段嵌套对象更稳
 */
/** @deprecated 用 ScriptContext —— 稳健档输入 = 通用 ScriptContext(保留别名,兼容现有引用) */
export type DraftPlanScriptInput = ScriptContext;

export interface DraftPlanScriptOutput {
  /** 整体语气标签(给客服参考) */
  tone: 'warm' | 'professional' | 'urgent';

  /** 第一部分·开场白 markdown(以医生名义 + 智能称呼 + 智能日期 + 自报家门) */
  opening: string;

  /** 第二部分·告知应治未治 markdown(成人 4 句/儿童 5 句:现状/风险/关怀/专业建议,只讲单个应治未治项) */
  informMissed: string;

  /** 第三部分·复查建议 markdown(成人 4 句/儿童 5 句:重要性/维护/复查时长/引导预约【时间段】) */
  reviewAdvice: string;

  /** 第四部分·结束回访语 markdown(预约成功 / 不成功 两种) */
  closing: string;
}
