import { liveDaysSince, applyLiveDays } from '@pac/types';

/**
 * 召回理由"距今天数"实时化(修"召回 388 / 治疗链 389 差一天"漂移)。
 *
 * 根因:plan 生成那一刻把 daysSince 算好写死进 signals(快照),随天数推移陈旧;
 *       治疗链断口(gapDays)是 read 时刻实时算的 → 两数差 = 中间过了几天。
 * 修法:signals 存不可变锚点 signalOccurredAt,展示层用 chain 同款公式实时重算。
 */
describe('reason live daysSince', () => {
  const NOW = new Date('2026-05-30T01:31:00Z');
  const OCCURRED = '2025-05-06T00:00:00Z'; // 吴远 K07 诊断日

  test('liveDaysSince 跟 chain gapDays 同款 floor 公式(2025-05-06 → 2026-05-30 = 389)', () => {
    expect(liveDaysSince(OCCURRED, NOW)).toBe(389);
  });

  test('liveDaysSince 与 chain-composer 公式逐位等价(Math.floor((now-occurred)/一天))', () => {
    const chainGap = Math.floor((NOW.getTime() - new Date(OCCURRED).getTime()) / 86_400_000);
    expect(liveDaysSince(OCCURRED, NOW)).toBe(chainGap);
  });

  test('无锚点 → null(调用方回落 baked daysSince,不回归)', () => {
    expect(liveDaysSince(null, NOW)).toBeNull();
    expect(liveDaysSince(undefined, NOW)).toBeNull();
    expect(liveDaysSince('not-a-date', NOW)).toBeNull();
  });

  test('未来锚点 clamp 到 0(防负数,满足 schema nonnegative)', () => {
    expect(liveDaysSince('2099-01-01T00:00:00Z', NOW)).toBe(0);
  });

  test('applyLiveDays:有锚点覆盖 daysSince 为实时值(388 快照 → 389 实时)', () => {
    const baked = {
      subKey: 'ortho_no_consult',
      triggers: [{ type: 'diagnosis', code: 'K07' }],
      toothPosition: null,
      daysSince: 388, // 昨天生成时的快照
      signalOccurredAt: OCCURRED,
      expectedCategories: ['orthodontic'],
    };
    const live = applyLiveDays(baked, NOW);
    expect(live?.daysSince).toBe(389);
    // 不可变:原对象不动
    expect(baked.daysSince).toBe(388);
  });

  test('applyLiveDays:无锚点(旧 plan)→ 原样返回 baked', () => {
    const oldPlan = {
      subKey: 'ortho_no_consult',
      triggers: [{ type: 'diagnosis', code: 'K07' }],
      daysSince: 388,
      expectedCategories: ['orthodontic'],
    };
    const out = applyLiveDays(oldPlan, NOW);
    expect(out?.daysSince).toBe(388);
    expect(out).toBe(oldPlan); // 引用不变(无锚点不拷贝)
  });

  test('applyLiveDays:null 透传', () => {
    expect(applyLiveDays(null, NOW)).toBeNull();
  });
});
