/**
 * Persona Feature Registry(标签注册表)— 单一真理源(代码,git/PR review)
 *
 * 画像的核心是「标签化」。每个标签按业务整理好的「标签卡」形式定义(对齐 CDP 标签中台 / OneModel):
 *   标签值 / 数据来源 / 数据字段 / 标签释义 / 计算算法 + 时间语义 / 层级 / owner / version。
 *
 * - 存储:**代码常量**(本文件),不落库;DB(persona_features)只存每患者每标签的实例值。
 * - 时间语义:每个标签自己声明(snapshot 当前态 / window 窗口 / lifetime 全史 / trend 趋势 / mixed)。
 * - 收口:producer 产出的 key 必须在此登记(CI 防漂移,见 persona-design-v2.md §二)。
 * - 来源可切:同一标签现可从 PAC 事实层自算,宿主 CDP 报表给出后切宿主值,口径(算法)不变。
 */
export type FeatureTier = 'rule' | 'statistical' | 'model' | 'llm';
export type FeatureTimeSemantics = 'snapshot' | 'window' | 'lifetime' | 'trend' | 'mixed';

export interface PersonaFeatureSpec {
  key: string; // PersonaFeatureKey
  nameZh: string; // 标签名
  tier: FeatureTier; // 层级:规则 / 统计 / 模型 / LLM
  timeSemantics: FeatureTimeSemantics; // 时间语义
  labelValues?: string[]; // 标签值(枚举型标签)
  dataSource: string; // 数据来源(现状 + 未来切换)
  dataFields: string[]; // 数据字段
  meaning: string; // 标签释义
  algorithm: string; // 计算算法(口径,人读;真理实现在 extractor)
  owner: string;
  version: number;
}

export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
  // ── B.1.1 RFM 层级(业务整理好的 CDP 口径,直接采用)──
  rfm: {
    key: 'rfm',
    nameZh: '价值分群(RFM)',
    tier: 'statistical',
    timeSemantics: 'mixed', // R=snapshot(最近) F/M=lifetime
    labelValues: [
      '重要价值客户',
      '重要保持客户',
      '重要发展客户',
      '重要挽留客户',
      '一般价值客户',
      '一般保持客户',
      '一般发展客户',
      '低活跃客户',
    ],
    dataSource:
      '现:PAC 事实层自算(encounter/treatment(actual)/挂号 + payment/recharge/refund);未来:宿主 CDP「客户综合分析报表」直接给 R/F/M',
    dataFields: ['last_visit_time', 'visit_times', 'net_receipts_total'],
    meaning: '基于最近就诊时间(R)、就诊频次(F)、累计消费(M)三维度的客户价值分层',
    algorithm: [
      'Step1 R/F/M 得分(1-5):',
      '  R ≤540天=5 / 541-730=4 / 731-1095=3 / 1096-1460=2 / >1460=1',
      '  F ≥5次=5 / 3-4次=4 / 2次=2 / 1次=1',
      '  M 累计消费分位:TOP20%=5 / 20-40%=4 / 40-60%=3 / 60-80%=2 / BOTTOM20%=1(租户内分位)',
      'Step2 分层:',
      '  R≥4 F≥3 M≥4→重要价值 / R=3 F≥3 M≥4→重要保持 / R≥4 F=2 M≥4→重要发展 / R≤2 F≥3 M≥4→重要挽留',
      '  R≥4 F≥3 M<4→一般价值 / R=3 F≥3 M<4→一般保持 / R≥4 F=2 M<4→一般发展 / 其余(含 R≤2 任意)→低活跃',
    ].join('\n'),
    owner: 'pac-algo',
    version: 1,
  },

  // ── A.1.1 年龄段(业务 CDP 口径)──
  age_bracket: {
    key: 'age_bracket',
    nameZh: '年龄段',
    tier: 'rule',
    timeSemantics: 'snapshot', // 当下年龄(随时间增长,历史读版本流)
    labelValues: [
      '婴幼儿(0-3)',
      '学龄前(3-6)',
      '替牙期(7-11)',
      '青少年(12-17)',
      '青年(18-25)',
      '中青年(26-30)',
      '中年(31-45)',
      '中老年(46-55)',
      '老年(55+)',
    ],
    dataSource: '现:PAC patient.birthDate 自算;未来:宿主 CDP「客户综合分析报表」client_age 直接取',
    dataFields: ['client_age'],
    meaning: '按口腔治疗需求特征精细划分年龄层,匹配适龄项目与家庭决策模式',
    algorithm: [
      'client_age 直接取值(PAC 现从 birthDate 算周岁);区间(下界含,3/55 重叠归下一档,≥55→老年):',
      '0-2→婴幼儿 / 3-6→学龄前 / 7-11→替牙期 / 12-17→青少年 / 18-25→青年 /',
      '26-30→中青年 / 31-45→中年 / 46-54→中老年 / ≥55→老年',
    ].join('\n'),
    owner: 'pac-algo',
    version: 1,
  },

  // ── A.1.2 性别(业务 CDP 口径)──
  gender: {
    key: 'gender',
    nameZh: '性别',
    tier: 'rule',
    timeSemantics: 'snapshot',
    labelValues: ['男性', '女性', '未知'],
    dataSource: '现:PAC patient.gender 自映射;未来:宿主 CDP client_gender 直接取',
    dataFields: ['client_gender'],
    meaning: '客户生理性别,影响沟通话术与项目推荐',
    algorithm: 'client_gender 直接映射:"M"/"男"→男性;"F"/"女"→女性;其他→未知',
    owner: 'pac-algo',
    version: 1,
  },

  // ── A.2.1 获客渠道(业务 CDP 口径,L2 数仓已算)──
  acquisition_channel: {
    key: 'acquisition_channel',
    nameZh: '获客渠道',
    tier: 'rule',
    timeSemantics: 'snapshot', // 初诊来源一经判定不改
    labelValues: ['走入', '口碑客户', '集团销售渠道', '集团营销渠道', '地区营销渠道', '电商平台', '自媒体网络', '内部员工', '其他'],
    dataSource: 'DW fact_client_out.primary_category/sub_category(L2 数仓初诊来源)→ 摄入 PAC 副表 patient_profiles.acquisition_channel/sub(立柱标准枚举)',
    dataFields: ['primary_category', 'sub_category'],
    meaning: '客户首次到诊的获客来源,用于渠道价值分析。初诊来源一经判定不做二次改归类',
    algorithm: 'host primary_category 经 assembler enum_mapping 归一到 PAC 立柱标准(走入→walk_in 等);二级 sub_category 原值透传。冲突解决(数仓侧):推荐人 > 活动码/渠道码 > 客户类型',
    owner: 'pac-algo',
    version: 1,
  },
};
