import { normalizeCanonical, isIdLikeKey, stripFloatTail } from '../src/modules/sync/assembler/field-mapper';

/**
 * 宿主 id 被 float 化的防御 —— "676600.0" → "676600"。
 *
 * 事故(2026-07-28 19:19,测试服务器):
 *   FRIDAY 推 med_emr_info 时 patient_id 变成了浮点字符串(典型 pandas 症状:
 *   列含空值 → int64 提升成 float64 → 导出 "676600.0")。PAC 原样收下,
 *   患者索引查 "676600.0" 命中不了真档 "676600" → ensurePatientStub 建出无名幽灵患者。
 *   3 个幽灵档吸走 4224 条事务,其中一个带 2246 条诊断进了召回池、算了画像、
 *   生成「应治未治」计划排队等客服打电话 —— 而推送回执是干干净净的 failed=0。
 *
 * 归一放在 normalizeCanonical(所有摄入通道共用),所以 cold-import / push / pull /
 * reparse 行为一致。
 */
describe('宿主 id 去浮点尾巴', () => {
  describe('stripFloatTail', () => {
    test.each([
      ['676600.0', '676600'],
      ['676600.00', '676600'],
      ['0.0', '0'],
      ['-12.0', '-12'],
    ])('%s → %s', (input, expected) => {
      expect(stripFloatTail(input)).toBe(expected);
    });

    test.each([
      ['676600'],   // 本来就是整数写法
      ['676600.5'], // 真带小数 —— 说明是另一种问题,要让它显形而不是被悄悄改写
      ['A676600.0'], // 非纯数字前缀
      ['676600.0x'],
      [''],
      ['abc'],
    ])('%s 不改写', (input) => {
      expect(stripFloatTail(input)).toBeNull();
    });

    test('非字符串不处理(JSON number 676600.0 在 JS 里就是整数,String() 无尾巴)', () => {
      expect(stripFloatTail(676600)).toBeNull();
      expect(stripFloatTail(null)).toBeNull();
      expect(stripFloatTail(undefined)).toBeNull();
    });
  });

  describe('isIdLikeKey —— 用 `Id` 后缀约定,新增 canonical 字段自动纳入', () => {
    test.each(['externalId', 'patientExternalId', 'relatedExternalId', 'clinicId', 'doctorId'])(
      '%s 是身份字段',
      (k) => expect(isIdLikeKey(k)).toBe(true),
    );
    test.each(['name', 'phone', 'amountCents', 'occurredAt', 'Id', 'id'])(
      '%s 不是',
      (k) => expect(isIdLikeKey(k)).toBe(false),
    );
  });

  describe('normalizeCanonical 端到端', () => {
    const ctx = { amountUnit: 'yuan' as const, timezone: 'Asia/Shanghai' };

    test('⭐ 事故原样复现:patientExternalId "676600.0" 归一成 "676600"', () => {
      const out = normalizeCanonical(
        { externalId: 'e1', patientExternalId: '676600.0', clinicId: '9001.0' },
        'encounter',
        ctx,
      );
      expect(out.patientExternalId).toBe('676600');
      expect(out.clinicId).toBe('9001');
    });

    test('非 id 字段不受影响(金额仍走 yuan→cents,不被当成 id 截断)', () => {
      const out = normalizeCanonical(
        { externalId: '1.0', name: '3.0', amount: 12.5 },
        'payment',
        ctx,
      );
      expect(out.externalId).toBe('1');
      expect(out.name).toBe('3.0'); // 姓名字段原样,不碰
      expect(out.amount).toBe(1250); // 金额照常 ×100 转分,没被当成 id 截断
    });

    test('正常 id 不被改动', () => {
      const out = normalizeCanonical({ externalId: '676600', patientExternalId: 'P-001' }, 'patient', ctx);
      expect(out.externalId).toBe('676600');
      expect(out.patientExternalId).toBe('P-001');
    });
  });
});
