import {
  ANCHOR_MODE_META,
  TEMPERATURE_META,
  planScenarioLabel,
  potentialTreatmentCardLabel,
  type AnchorModeValue,
  type TemperatureValue,
} from '@pac/types';

/**
 * model-facing —— 服务层返回值 →「面向模型」的形状。
 *
 * ═══ 为什么要有这一层 ═══════════════════════════════════════════════
 * 模型说出 `cold_3y` `implant` `inHandPending` 这类词，主管的第一反应是**系统坏了**。
 * 原来的对策是在提示词里写两页「⛔ 不许说出取值码」——那是 P4 ③ 级（只拦得住预想到的），
 * 而且实测拦不住：模型调工具**必须**用码当参数，回话时自然就带出来了。
 *
 * 真正的解法是**给它现成的中文**：返回值里既回显它传进来的条件（`criteriaZh`），
 * 又把桶名换成中文键。它手里有话可说，就不会去说码。—— 这是 ① 级（结构上不可能）。
 *
 * ═══ 三条边界 ═══════════════════════════════════════════════════════
 * ⛔ **只做翻译，不做业务判断。** 任何"要不要提醒""算不算成功"的判断都不属于这里。
 * ⛔ **不改底层 service 的形状。** REST / 前端是另一个消费者，它们要的是稳定的 key。
 *    翻译只发生在 MCP 边界上。
 * ⛔ **不在这里生成成品句子。** 那是 P2 要消除的东西（G6：给事实不给句子）。
 *
 * 标签一律取自 `@pac/types` 的既有映射，⛔ 不在这里另立一套中文 —— 两份必然漂。
 */

// ─────────────────────────────────────────────────────────
// 单值翻译
// ─────────────────────────────────────────────────────────

/** 时间档取值码 → 矩阵上那一列的中文（`hot` → 「三个月内」） */
export function zhTemperature(code: string | null | undefined): string | null {
  if (!code) return null;
  return TEMPERATURE_META[code as TemperatureValue]?.zh ?? code;
}

/** 潜在治疗取值码 → 矩阵上那一行的中文（`implant` → 「种植」） */
export function zhTreatment(code: string | null | undefined): string | null {
  if (!code) return null;
  return potentialTreatmentCardLabel(code);
}

/** 召回场景取值码 → 中文（`treatment_initiation_recall` → 「潜在治疗」） */
export function zhScenario(code: string | null | undefined): string | null {
  if (!code) return null;
  return planScenarioLabel(code);
}

/** 档位口径 → 中文（`last_visit` → 「按末诊」） */
export function zhAnchorMode(code: string | null | undefined): string | null {
  if (!code) return null;
  return ANCHOR_MODE_META[code as AnchorModeValue]?.zh ?? code;
}

// ─────────────────────────────────────────────────────────
// 条件回显
// ─────────────────────────────────────────────────────────

/**
 * 把模型传进来的筛选条件原样回一份中文 —— **这是本模块最关键的一个函数**。
 *
 * 模型必须用码调工具（`temperature: 'hot'`），但回话要说「三个月内」。
 * 不给回显，它只能自己翻译；自己翻译就会翻错，或者干脆把码念出来。
 * ⇒ 每个吃这些条件的工具，返回值里都带一份 `criteriaZh`。
 *
 * [弥补模型]
 */
export function criteriaZh(input: {
  potentialTreatment?: string | null;
  temperature?: string | null;
  anchorMode?: string | null;
}): Record<string, string> {
  const out: Record<string, string> = {};
  const t = zhTreatment(input.potentialTreatment);
  const temp = zhTemperature(input.temperature);
  const anchor = zhAnchorMode(input.anchorMode);
  if (t) out['治疗项'] = t;
  if (temp) out['时间档'] = temp;
  if (anchor) out['口径'] = anchor;
  return out;
}

// ─────────────────────────────────────────────────────────
// 桶名翻译
// ─────────────────────────────────────────────────────────

/**
 * 批次处理进度的五个桶 → 中文键。
 *
 * ⚠️ 这几个词是提示词里被反复叮嘱的重灾区（`resolved` `suppressed` `inHandPending`
 * `backToPool`），因为它们既是内部枚举、又必须报给主管看。换成中文键之后，
 * 模型照着键名说就是对的。
 *
 * ⚠️ 中文键刻意写全「已出池」而不是「已完成」—— `resolved` 是**引擎判定召回需求没了**，
 * ⛔ 不是「谈成了」。键名本身就该挡住这个误读（T14）。
 *
 * [弥补模型]
 */
export function zhProgressBuckets(p: {
  done?: number;
  resolved?: number;
  suppressed?: number;
  closed?: number;
  inHandPending?: number;
  backToPool?: number;
  reassigned?: number;
  ageDays?: number;
}): Record<string, number> {
  const out: Record<string, number> = {};
  if (p.done !== undefined) out['已处理'] = p.done;
  if (p.resolved !== undefined) out['已出池·引擎判定需求已了'] = p.resolved;
  if (p.suppressed !== undefined) out['客服已写回访结果'] = p.suppressed;
  if (p.closed !== undefined) out['已结案'] = p.closed;
  if (p.inHandPending !== undefined) out['还在客服手上没动'] = p.inHandPending;
  if (p.backToPool !== undefined) out['退回或到期落回池子'] = p.backToPool;
  if (p.reassigned !== undefined) out['已被后续批次挑走'] = p.reassigned;
  if (p.ageDays !== undefined) out['本批已跑天数'] = p.ageDays;
  return out;
}

/**
 * 画像维度里的 `noTag` → 中文键。
 *
 * ⚠️ 「没有这条记录」而不是「无标签」：`noTag` 是**没有这条画像证据**，
 * ⛔ 不是反面（「没有商保标签」≠「自费」）。这是提示词里最长的一条护栏，
 * 键名写清楚就少一次误读。
 *
 * [弥补模型]
 */
export function zhCohortDim<T extends { id: string; nameZh: string; noTag: number; multi: boolean }>(
  dim: T,
): Omit<T, 'noTag' | 'multi'> & { 没有这条记录的人数: number; 一人可命中多项: boolean } {
  const { noTag, multi, ...rest } = dim;
  return { ...rest, 没有这条记录的人数: noTag, 一人可命中多项: multi };
}
