/**
 * agent-identity —— 「自报家门」客服身份的**单一源**(稳健 / 标准 / 深度三档共用)。
 *
 * ## 为什么要占位符(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 原样输出,渲染期按当前登录客服回填 */
export const AGENT_IDENTITY_PLACEHOLDER = '【回访客服】';

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

/** 自报家门用的客服身份:岗位称呼 + 姓名(姓名可空) */
export interface ScriptAgentIdentity {
  /** 宿主 users 字典里的姓名(如"李倩");字典缺失 → null,回填退回通用"客服" */
  name: string | null;
  /** 患者侧岗位称呼(员工/管理员→客服;主管→客服主管) */
  roleTitle: string;
}

/** JWT role → 患者侧岗位称呼。宿主角色与患者称呼是两件事,别把 admin 报成"管理员"。 */
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;
}
