/**
 * script-facts — 把"参考话术"提示词里**本该程序判断的确定性逻辑**提取成纯函数 + 字典。
 *
 * 设计原则(渐进式组合 + 提示词缓存):
 *   - LLM 不再做:年龄分支 / 智能日期格式 / 漏诊项优先级挑选 / 查 key-points 表 / 查复查时长 / 智能称呼。
 *     这些全在这里算好,作为"已定事实"塞进 user prompt,LLM 只负责把事实润色成话术。
 *   - 静态铁律/模板 → system(base-system.md + population skill,前缀缓存);
 *     本文件算出的"单个患者相关"事实 → user(动态,渐进式只给相关的那一条,不发全表)。
 *
 * 真理源:文案要点来自业务给的"漏诊项目关键要点配置 / 复查时长配置 / 年龄组配置"。
 */

// ─────────────────────────────────────────────────────────
// 年龄分支(儿童 ≤12 / 成人 ≥13;未知 → 成人)
// ─────────────────────────────────────────────────────────
export type AgeBranch = 'child' | 'adult';

export function resolveAgeBranch(age: number | null | undefined): AgeBranch {
  if (typeof age === 'number' && Number.isFinite(age)) return age <= 12 ? 'child' : 'adult';
  return 'adult'; // 未知 / 模糊 → 默认成人漏诊模板
}

/** 年龄组(成人 key-points 的"年龄适应性"用) */
export function resolveAgeGroup(age: number | null | undefined): '青年' | '中年' | '老年' | null {
  if (typeof age !== 'number' || !Number.isFinite(age)) return null;
  if (age >= 60) return '老年';
  if (age >= 36) return '中年';
  if (age >= 18) return '青年';
  return null; // 儿童/青少年走儿童模板,这里不给成人年龄适应性
}

// ─────────────────────────────────────────────────────────
// 智能日期显示(今年→X月X号 / 去年→去年X月 / 更早→XXXX年X月)
//   —— 替代提示词里那段 python datetime 函数(LLM 不该跑日期逻辑)
// ─────────────────────────────────────────────────────────
export function smartDateDisplay(visit: Date | string | null | undefined, now: Date): string | null {
  if (!visit) return null;
  const d = visit instanceof Date ? visit : new Date(visit);
  if (Number.isNaN(d.getTime())) return null;
  const m = d.getMonth() + 1;
  if (d.getFullYear() === now.getFullYear()) return `${m}月${d.getDate()}号`;
  if (d.getFullYear() === now.getFullYear() - 1) return `去年${m}月`;
  return `${d.getFullYear()}年${m}月`;
}

// ─────────────────────────────────────────────────────────
// 智能称呼(成人→{姓}先生/女士 · 儿童→{姓名}家长 · 未知→您好)
//   nameMasked 已脱敏(如"侯*"),取首字作姓;脱敏掉首字则回退"您好"
// ─────────────────────────────────────────────────────────
export function resolveSalutation(params: {
  nameMasked: string | null | undefined;
  gender: string | null | undefined;
  branch: AgeBranch;
}): string {
  const { nameMasked, gender, branch } = params;
  const surname = (nameMasked ?? '').trim().charAt(0);
  if (branch === 'child') {
    return surname ? `${surname}家长` : '您好';
  }
  const g = (gender ?? '').trim();
  if (!surname || (g !== '男' && g !== '女' && g.toUpperCase() !== 'M' && g.toUpperCase() !== 'F')) {
    return '您好';
  }
  const honorific = g === '男' || g.toUpperCase() === 'M' ? '先生' : '女士';
  return `${surname}${honorific}`;
}

// ─────────────────────────────────────────────────────────
// 漏诊项关键要点配置(成人模板"告知漏诊项目"小节2/3 灵活组合用)
//   渐进式披露:user prompt 只塞**命中那一个病种**的要点,不发全表。
// ─────────────────────────────────────────────────────────
export interface MissedKeyPoints {
  /** 风险要点(口语化,2-4 条灵活组合) */
  risks: string[];
  /** 治疗优势要点(趁现在/早处理) */
  advantages: string[];
  /** 年龄适应性(可选,按 resolveAgeGroup 取一句) */
  ageFit?: Partial<Record<'青年' | '中年' | '老年', string>>;
}

export const MISSED_DIAGNOSIS_KEY_POINTS: Record<string, MissedKeyPoints> = {
  牙槽骨吸收: {
    risks: [
      '时间久了,牙齿容易松动,吃东西会不太舒服',
      '牙缝可能慢慢变大,食物容易卡进去',
      '如果放着不管,牙齿还有脱落的风险',
      '可能需要拔牙再种,医生说这样治疗周期会更长',
      '后面如果骨头吸收严重了,想要做修复就比较难了',
    ],
    advantages: ['趁现在早处理,能稳住牙槽骨', '早一点介入,对牙齿稳定有帮助,也避免将来多花功夫'],
    ageFit: { 青年: '年轻时治疗效果更好', 中年: '正是关键时期,及时治疗很重要', 老年: '虽然年龄大了,但治疗仍有意义' },
  },
  缺失牙: {
    risks: [
      '缺牙的地方如果不处理,旁边的牙齿可能会慢慢歪掉',
      '上面的牙齿还可能伸长出来,位置就不对了',
      '时间一长,吃东西也会不太舒服,容易咬不到位',
      '食物卡得多了,还容易蛀牙、牙周炎',
      '不修复的话骨头会萎缩,后面再想种牙就困难一些',
    ],
    advantages: ['及时修复能恢复咀嚼、保护邻牙', '趁现在牙槽骨条件还不错,早点处理效果更好'],
    ageFit: { 青年: '年轻时修复适应性强', 中年: '正值事业期,形象很重要', 老年: '晚年生活质量需要保障' },
  },
  残根: {
    risks: ['长时间不处理可能引发反复炎症', '容易形成慢性牙龈肿痛', '可能影响邻牙健康', '后期拔除难度会增加'],
    advantages: ['越早处理越简单', '避免引发急性疼痛', '减少对邻牙的影响'],
  },
  残冠: {
    risks: ['容易堆积食物导致反复牙龈炎', '可能出现牙齿折裂扩大损伤', '影响咬合舒适度'],
    advantages: ['及时处理避免二次损伤', '利于后续修复效果', '咬合功能更稳定'],
  },
  囊肿: {
    risks: ['如果持续增大可能压迫周围组织', '容易导致骨吸收', '可能影响邻牙位置', '拖久了处理范围会更大'],
    advantages: ['及早关注避免扩大范围', '早期处理恢复更快', '减少对周围骨组织的破坏'],
  },
  根尖周炎: {
    risks: ['容易导致持续性咬牙痛', '可能形成小脓包或脸肿', '长期不处理会影响其他牙', '感染可能逐渐加重'],
    advantages: ['越早处理越容易控制炎症', '避免发展成急性疼痛', '能更好地保住这颗牙'],
  },
  乳牙滞留: {
    risks: ['可能影响恒牙正常萌出', '易导致牙列不齐', '恒牙可能被挤偏'],
    advantages: ['及时处理更有利于恒牙发育', '减少以后矫正难度', '让牙列更整齐'],
  },
  楔状缺损: {
    risks: ['越磨越深可能导致牙髓敏感', '长期易出现冷热敏感', '咬合压力不均会加重缺损'],
    advantages: ['越早处理越容易控制敏感', '可以保护牙体结构', '改善咬合舒适度'],
  },
  龋齿: {
    risks: ['如果放任不管会越变越深', '可能引发牙痛或感染', '可能需要更复杂的治疗'],
    advantages: ['早处理范围小、恢复快', '能避免发展成根管问题', '保持牙齿长期稳定'],
  },
  阻生牙: {
    risks: ['可能反复发炎肿痛', '挤压邻牙导致牙列不齐', '可能形成囊肿或引发感染'],
    advantages: ['早观察早处理更安全', '减少发炎频率', '避免推挤邻牙'],
  },
  埋伏牙: {
    risks: ['可能影响周围牙根结构', '容易引发局部炎症', '可能挤压造成牙列拥挤'],
    advantages: ['早期监测干预更安全', '减少后期并发症', '利于牙列整体稳定'],
  },
  多生牙: {
    risks: ['可能阻挡恒牙正常萌出', '会影响邻牙位置', '可能导致牙列拥挤'],
    advantages: ['越早处理越不影响恒牙', '减少后期矫正难度', '让牙列发育更顺畅'],
  },
  // ── 补齐 PAC 子场景(应治未治)对应的口径 ──
  牙周炎: {
    risks: [
      '牙龈容易出血、红肿,刷牙时尤其明显',
      '时间久了牙槽骨吸收,牙齿会慢慢松动',
      '牙缝可能变大,食物容易塞牙',
      '不控制的话,后面可能要拔牙',
    ],
    advantages: ['趁现在做基础治疗,能把炎症控制住', '早点干预,牙齿能保留得更久'],
    ageFit: { 青年: '年轻时牙周恢复能力强', 中年: '正是该好好维护的时候', 老年: '维护好牙周,晚年吃东西更舒服' },
  },
  错颌畸形: {
    risks: [
      '牙齿排列不齐,刷牙容易刷不干净,易蛀牙、牙龈发炎',
      '咬合不好,长期可能影响咀嚼和颞下颌关节',
      '也会影响笑容和自信',
    ],
    advantages: ['早点评估,矫治方案选择更多', '趁现在牙周条件好,矫正更稳'],
    ageFit: { 青年: '年轻时矫正配合度和效果都更好', 中年: '成人也能做隐形矫正,不影响工作' },
  },
  牙体损伤: {
    risks: ['缺损放着不管会越来越大', '可能出现冷热敏感或牙痛', '严重了可能伤到牙神经,要做根管'],
    advantages: ['早修复范围小、花费少', '能保护剩余牙体,避免折裂'],
  },
  牙龈问题: {
    risks: ['牙龈反复红肿出血', '可能慢慢退缩,牙根暴露敏感', '不处理会影响牙齿稳固'],
    advantages: ['早处理容易控制', '保护牙龈和牙槽骨健康'],
  },
  恒牙萌出空间不足: {
    risks: ['恒牙可能没地方长,容易长歪或拥挤', '将来矫正难度会更大'],
    advantages: ['趁换牙期早干预,引导恒牙顺利萌出', '减少以后正畸的复杂程度'],
  },
  儿牙早矫: {
    risks: ['不良习惯或颌骨发育问题越拖越难纠正', '可能影响恒牙排列和脸型发育'],
    advantages: ['替牙期是早矫黄金期,效果好、周期短', '趁现在引导,省去将来复杂矫正'],
  },
};

// ─────────────────────────────────────────────────────────
// 复查时长配置(非治疗时长)— "复查建议·检查说明"小节用
// ─────────────────────────────────────────────────────────
export const TREATMENT_DURATION: Record<string, string> = {
  儿牙早矫: '复查检查约30-45分钟,医生会详细评估宝宝的恒牙萌出情况和间隙保持需求',
  恒牙萌出空间不足: '复查检查约30分钟,医生会详细评估恒牙萌出情况',
  缺失牙: '复查检查约30分钟,了解缺失牙位目前状况',
  牙槽骨吸收: '复查检查约30-45分钟,需要仔细检查牙周健康状况',
  牙周病: '复查检查约30-45分钟,评估牙周健康情况',
  牙周炎: '复查检查约30-45分钟,评估牙周健康情况',
  错颌畸形: '复查检查约30分钟,医生评估咬合与矫治方案',
  牙体损伤: '复查检查约20-30分钟,查看牙体缺损情况',
  根尖周炎: '复查检查约20-30分钟,查看牙髓和根尖情况',
  牙龈问题: '复查检查约20-30分钟,评估牙龈健康',
  阻生牙: '复查检查约20-30分钟,评估阻生牙位置',
  颌骨囊肿: '复查检查约30分钟,评估囊肿范围',
  龋齿: '复查检查约20-30分钟,查看牙齿状况',
  其他: '复查检查约30分钟',
};

// ─────────────────────────────────────────────────────────
// ⭐ 转换层:PAC 召回 reason(应治未治)→ 漏诊项口径
//   "漏诊项" 在 PAC = treatment_initiation_recall 的 reason(K00-K09 应治未治)。
//   reason.subKey(子场景)→ 配置 key(查 key-points/复查时长)+ 患者口径 label。
//   PAC 已按 priorityScore 给 reason 排序 → 主漏诊项 = 排第一的 reason(不另用业务硬优先级)。
// ─────────────────────────────────────────────────────────
const SUBKEY_TO_MISSED: Record<string, { key: string; label: string }> = {
  missing_tooth: { key: '缺失牙', label: '缺失牙' },
  caries_no_filling: { key: '龋齿', label: '龋齿' },
  endo_no_rct: { key: '根尖周炎', label: '牙髓/根尖周炎' },
  perio_no_srp: { key: '牙周炎', label: '牙周炎' },
  ortho_no_consult: { key: '错颌畸形', label: '错颌畸形（牙齿不齐）' },
  hard_tissue_damage: { key: '牙体损伤', label: '牙体缺损' },
  gum_alveolar_lesion: { key: '牙龈问题', label: '牙龈/牙槽问题' },
  impacted_tooth: { key: '阻生牙', label: '阻生牙' },
  jaw_cyst: { key: '颌骨囊肿', label: '颌骨囊肿' },
  development_eruption: { key: '恒牙萌出空间不足', label: '牙齿萌出异常' },
};

export interface MissedItem {
  /** 患者口径漏诊项(话术里用,如"缺失牙""错颌畸形(牙齿不齐)") */
  label: string;
  /** 配置 key(查 key-points / 复查时长);null = 未映射,用 label 兜底 */
  key: string | null;
}

/** 单条 PAC reason → 漏诊项(subKey 优先,缺失则用文本兜底归一) */
export function missedFromReason(reason: {
  subKey?: string | null;
  dxCode?: string | null;
  reason?: string | null;
  scenarioLabel?: string | null;
}): MissedItem {
  // subKey 可能带 @tooth 后缀(如 caries_no_filling@36)→ 取前缀
  const baseSub = (reason.subKey ?? '').split('@')[0]!.trim();
  const mapped = baseSub ? SUBKEY_TO_MISSED[baseSub] : undefined;
  if (mapped) return { label: mapped.label, key: mapped.key };
  // 兜底:从 reason/scenarioLabel 文本归一
  const text = `${reason.scenarioLabel ?? ''} ${reason.reason ?? ''}`;
  const key = canonicalMissedKey(text);
  return { label: key ?? (reason.scenarioLabel ?? '需复查的问题'), key };
}

// ─────────────────────────────────────────────────────────
// 漏诊项归一 + 优先级挑选
//   漏诊项文本(如"牙位:21,牙槽骨吸收")→ 命中配置 key(includes 关键词)
//   优先级:儿牙早矫 > 恒牙萌出空间不足 > 缺失牙 > 牙槽骨吸收 > 其余(配置出现顺序)
// ─────────────────────────────────────────────────────────
const MISSED_PRIORITY = ['儿牙早矫', '恒牙萌出空间不足', '缺失牙', '牙槽骨吸收'];

/** 把一条漏诊项文本归一到配置 key(找不到 → null,文案兜底用原文) */
export function canonicalMissedKey(missedText: string | null | undefined): string | null {
  const s = (missedText ?? '').trim();
  if (!s) return null;
  const keys = [...new Set([...MISSED_PRIORITY, ...Object.keys(MISSED_DIAGNOSIS_KEY_POINTS), ...Object.keys(TREATMENT_DURATION)])];
  for (const k of keys) if (s.includes(k)) return k;
  return null;
}

/** 从多条漏诊项里按优先级挑**一个**主漏诊项(LLM 只聚焦这一个) */
export function pickPrimaryMissed(items: Array<string | null | undefined>): { raw: string; key: string | null } | null {
  const cleaned = items.map((x) => (x ?? '').trim()).filter(Boolean);
  if (cleaned.length === 0) return null;
  // 先按优先级关键词找
  for (const p of MISSED_PRIORITY) {
    const hit = cleaned.find((x) => x.includes(p));
    if (hit) return { raw: hit, key: p };
  }
  // 否则取第一条,尽量归一
  const first = cleaned[0]!;
  return { raw: first, key: canonicalMissedKey(first) };
}

export function lookupKeyPoints(key: string | null): MissedKeyPoints | null {
  return key ? (MISSED_DIAGNOSIS_KEY_POINTS[key] ?? null) : null;
}

export function lookupReviewDuration(key: string | null): string {
  return (key && TREATMENT_DURATION[key]) || TREATMENT_DURATION['其他']!;
}
