/**
 * agent-identity —— 「自报家门」身份的**单一源**(稳健 / 标准 / 深度三档共用)。
 *
 * ## 患者侧身份 = 「某医生的助理」,不是「客服」(业务口径 2026-07-29)
 * 完整一句是「我是{诊断医生}医生的助理{姓名}」—— 拼装在各档 prompt 里,本文件只管后半截身份。
 * 换法的理由是业务定的:回访电话挂医生的名义,患者更愿意接、也更接近事实(话术全程以
 * 诊断医生的关怀为主线);"客服"听起来像销售,开场就掉信任。
 * ⚠️ 岗位称呼不再区分 staff/leader —— 患者不关心内部层级,统一"助理"。
 *
 * ## 为什么要占位符(2026-07 线上 bug)
 * 原设计把登录客服的姓名直接烤进 LLM 生成的话术正文(v9:"我是X诊所的客服主管晋芳辰")。
 * 但 `plan_scripts` 的 UNIQUE 是 **plan_id** —— 一个 plan 只有一份话术、不分人;而召回池是**共享**的,
 * 未认领工单谁都能打开。结果:晋芳辰先打开触发生成 → 姓名固化进正文 → 李倩后打开读到同一份缓存,
 * 话术里自报家门成了别人的名字。线上 44 条话术 100% 中招,是必然而非偶发。
 *
 * ## 解法:姓名不进 LLM,改「生成期占位 → 渲染期回填」
 *   - **生成期**:prompt 只给占位符 {@link AGENT_IDENTITY_PLACEHOLDER},LLM 原样输出,落库正文不含人名。
 *   - **渲染期**:内容出服务前按**当前登录人**替换({@link renderAgentIdentity})。谁看都对。
 *
 * 顺带两个好处:
 *   1. `input_hash` 不再含人名 → 同一 plan 不同客服命中同一 AI 缓存(原来每人各烧一次 LLM)。
 *   2. 工单回收/转派后话术里的名字自动跟着换,不用重新生成。
 *
 * ## 占位符约定(沿用 v8 立的规矩)
 *   `{xxx}` = prompt 内**填空**(LLM 替换掉,不进输出)
 *   `【xxx】` = **原样保留到输出**;其消费者有两类 ——
 *       · 客服手填:【时间段1】【时间段2】【具体预约时间】(诊所无排班接口,时间不写死)
 *       · 系统回填:【回访客服】(本文件)—— 对 LLM 的契约完全一致:原样输出、别自己编名字。
 */

/**
 * 自报家门占位符 —— LLM 原样输出,渲染期按当前登录人回填。
 *
 * ⚠️ 字面量仍是「回访客服」是**故意不动的**:线上 plan_scripts 里已有的正文都含这串,
 * 改字面量 = 老缓存回填不上、患者会看到光秃秃的占位符。它现在只是个 token,
 * 回填出来的内容已经是"助理X"(见 ROLE_TITLE_ZH)。
 */
export const AGENT_IDENTITY_PLACEHOLDER = '【回访客服】';

/** 无姓名时的兜底称谓(宿主未下发 users 字典 / 匿名调用)—— 不编名字,只报岗位 */
export const AGENT_IDENTITY_FALLBACK = '助理';

/** 自报家门用的身份:岗位称呼 + 姓名(姓名可空) */
export interface ScriptAgentIdentity {
  /** 宿主 users 字典里的姓名(如"李倩");字典缺失 → null,回填退回通用"助理" */
  name: string | null;
  /** 患者侧岗位称呼 —— 一律"助理"(见文件头:患者不关心内部层级) */
  roleTitle: string;
}

/**
 * JWT role → 患者侧岗位称呼。宿主角色与患者称呼是两件事,别把 admin 报成"管理员"。
 * 三种角色现在同值 —— 表保留是因为"将来某类角色要换称呼"仍是这里改,不是散到各档 prompt。
 */
const ROLE_TITLE_ZH: Record<string, string> = {
  staff: '助理',
  leader: '助理',
  admin: '助理',
};

/**
 * 登录用户 → 自报家门身份。
 * 取最小形状(不依赖 AuthenticatedUser 具名类型)便于 ai 层复用 + 单测。
 */
export function resolveScriptAgent(user: {
  sub: string;
  role: string;
  dictionary?: { users?: Record<string, string> };
}): ScriptAgentIdentity {
  return {
    name: user.dictionary?.users?.[user.sub]?.trim() || null,
    roleTitle: ROLE_TITLE_ZH[user.role] ?? AGENT_IDENTITY_FALLBACK,
  };
}

/** 身份 → 落到话术里的那串字(有名字报"助理李倩";没名字只报"助理",绝不编) */
export function agentIdentityText(agent: ScriptAgentIdentity | null | undefined): string {
  if (!agent?.name) return AGENT_IDENTITY_FALLBACK;
  return `${agent.roleTitle}${agent.name}`;
}

/**
 * 渲染期回填 —— 话术正文里的 {@link AGENT_IDENTITY_PLACEHOLDER} 换成当前登录人。
 * agent 缺省(内部调用 / 无登录态)→ 换成通用"助理",**不留占位符给患者看到**。
 */
export function renderAgentIdentity<T extends string | null | undefined>(
  content: T,
  agent?: ScriptAgentIdentity | null,
): T {
  if (!content || !content.includes(AGENT_IDENTITY_PLACEHOLDER)) return content;
  return content.split(AGENT_IDENTITY_PLACEHOLDER).join(agentIdentityText(agent)) as T;
}
