import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import {
  HOST_ACTION_MESSAGE_SOURCE,
  HOST_ACTION_MESSAGE_TYPE,
  HOST_CASE_STAGE_CONSULTED,
  POTENTIAL_TREATMENT_CARD_LABEL,
  potentialTreatmentItemName,
} from '@pac/types';

/**
 * postMessage 动作契约 ↔ 交付文档 防漂移。
 *
 * 这份契约是**发给宿主开发照着写监听**的,漂了不会在 PAC 里报错 —— 只会让对方按文档写完发现
 * 收不到 / 值对不上,而且要等到联调才暴露。所以拿测试盯住三件事:
 *   ① 信封固定字段(source/type)别改字面 —— 宿主是按它过滤的
 *   ② 病例阶段恒「已咨询」—— 文档承诺了"恒为",代码里改成别的值就是骗人
 *   ③ 8 类治疗项目的**项目名和稳定 code 都要在文档里列全** ——
 *      改措辞(labels.ts)或加一类,交付文档必须同步,否则宿主的映射表会缺项。
 *      注意查的是**项目名**(去「治疗」后缀)而不是卡片标签:发出去的是前者,
 *      文档要跟载荷一致,不是跟界面一致
 */
const DOC = readFileSync(
  join(__dirname, '../../pac-docs/content/docs/integration/postmessage-actions.mdx'),
  'utf-8',
);

describe('postMessage 动作契约 ↔ 交付文档', () => {
  test('⭐ 信封固定字段不许改字面(宿主按 source+type 过滤)', () => {
    expect(HOST_ACTION_MESSAGE_SOURCE).toBe('pac');
    expect(HOST_ACTION_MESSAGE_TYPE).toBe('action');
    expect(DOC).toContain("source: 'pac'");
    expect(DOC).toContain("type: 'action'");
  });

  test('⭐ 病例阶段恒「已咨询」—— 文档承诺了"恒为",代码不能偷偷换值', () => {
    expect(HOST_CASE_STAGE_CONSULTED).toBe('已咨询');
    expect(DOC).toContain('已咨询');
  });

  test('⭐ 8 类治疗项目的项目名 + 稳定 code 都要在交付文档里列全', () => {
    const missing: string[] = [];
    for (const code of Object.keys(POTENTIAL_TREATMENT_CARD_LABEL)) {
      const item = potentialTreatmentItemName(code);
      if (!DOC.includes(`| ${item} |`)) missing.push(`项目名「${item}」`);
      if (!DOC.includes(`\`${code}\``)) missing.push(`code \`${code}\``);
    }
    expect(missing).toEqual([]);
  });

  test('⭐ 项目名不带「治疗」后缀、不出空串', () => {
    for (const code of Object.keys(POTENTIAL_TREATMENT_CARD_LABEL)) {
      const item = potentialTreatmentItemName(code);
      expect(item.length).toBeGreaterThan(0);
      expect(item.endsWith('治疗')).toBe(false);
    }
    expect(potentialTreatmentItemName('implant')).toBe('种植');
    // 早矫是例外(卡片叫「早期矫治」,砍后缀砍不出来)—— 锁住,别哪天被"统一成推导"改回去
    expect(potentialTreatmentItemName('early_ortho')).toBe('早矫');
  });

  test('⭐ 载荷字段名就是 desc / treatments / stage —— 改名等于毁约,宿主的解构会拿到 undefined', () => {
    for (const f of ['`desc`', '`treatments`', '`stage`']) expect(DOC).toContain(f);
    // 旧名字不许还留在交付文档里(留着对方会照旧名写)
    for (const old of ['pendingTreatmentDesc', 'potentialTreatments', 'caseStage']) {
      expect(DOC).not.toContain(old);
    }
  });

  test('文档给出了 origin 校验示例 —— 少这一句宿主就等于开后门', () => {
    expect(DOC).toContain('e.origin');
  });
});
