import { EXECUTION_OUTCOME_META, EXECUTION_OUTCOME_GROUP_META } from '@pac/types';

/**
 * 执行结果的**归类**与**状态机**是两件事,这个 spec 锁的就是它们的分离。
 *
 * 🔴 `scheduled_next`(约定下次回访)是唯一一个 `group` 与 `drivesStatus` **故意不一致**的项:
 *     group:        'close'  —— 统计口径:约到下次是**有效推进**,不该跟"未接通/秒挂"一起算「保持」
 *     drivesStatus: 'keep'   —— 状态机:工单必须留着并 snooze 到回访日
 *   看着像笔误,所以极可能被后来的人"顺手改一致"。而改成 'completed' 的后果是:
 *   客服刚答应了患者"那天再联系您",这单却当场出池,**约好的回访再也不会发生**,且不报错。
 */
describe('执行结果分类 —— 归类口径 ≠ 状态机', () => {
  test('⭐⭐ 约定下次回访:算「成功」但**不结案**', () => {
    const m = EXECUTION_OUTCOME_META.scheduled_next;
    expect(m.group).toBe('close'); // 统计上算成功
    expect(m.drivesStatus).toBe('keep'); // ⛔ 绝不能是 completed
  });

  test('⭐ 转化新预约:算「成功」且结案(顶栏「预约」快速记录落的就是它)', () => {
    const m = EXECUTION_OUTCOME_META.success_appointed;
    expect(m.group).toBe('close');
    expect(m.drivesStatus).toBe('completed');
  });

  test('「保持」组里只剩真正没进展的(未接通 / 秒挂)', () => {
    const keep = Object.entries(EXECUTION_OUTCOME_META)
      .filter(([, m]) => m.group === 'keep' && !m.hiddenInForm)
      .map(([k]) => k)
      .sort();
    expect(keep).toEqual(['no_answer', 'quick_hangup']);
  });

  test('⛔ 归到「成功」组的,要么结案、要么留单 —— 但**绝不能**是 abandoned', () => {
    // abandoned 是"放弃",出现在成功组等于把放弃算成成功,统计当场反向
    for (const [key, m] of Object.entries(EXECUTION_OUTCOME_META)) {
      if (m.group === 'close') {
        expect([key, m.drivesStatus]).not.toEqual([key, 'abandoned']);
      }
    }
  });

  test('每个 outcome 的 group 都必须是已登记的组(拼错会静默从面板消失)', () => {
    const groups = new Set(Object.keys(EXECUTION_OUTCOME_GROUP_META));
    for (const [key, m] of Object.entries(EXECUTION_OUTCOME_META)) {
      expect([key, groups.has(m.group)]).toEqual([key, true]);
    }
  });
});
