/**
 * 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,
  },

  // ── A.3.1 家庭构成(业务 CDP 口径;PAC 用 PatientRelation 反推)──
  family_structure: {
    key: 'family_structure',
    nameZh: '家庭构成',
    tier: 'rule',
    timeSemantics: 'snapshot',
    labelValues: ['单身家庭', '两口之家', '多口之家', '多代之家'],
    dataSource: '现:PAC PatientRelation 边表(摄入自 fact_customer_referee_out,混推荐人噪音);未来:宿主 CDP「社交关系维护」social_relations',
    dataFields: ['social_relations'],
    meaning: '基于直系亲属社交关系反推家庭结构,用于家庭套餐推荐与儿牙营销',
    algorithm: [
      '直系:spouse / child·grandchild / father·mother·grandparent;sibling/friend/other 不计(噪音)。',
      '有长辈→多代之家;否则有子女→多口之家;否则有配偶→两口之家;否则有非直系边→单身家庭;无边→不打标签。',
      '⚠️ 依赖关系边覆盖,样本稀疏 + 非全量时覆盖偏低。',
    ].join('\n'),
    owner: 'pac-algo',
    version: 1,
  },

  // ── B.1.2 转介绍达人(业务 CDP 口径;v1 用 DW 预聚合)──
  referral_champion: {
    key: 'referral_champion',
    nameZh: '转介绍达人',
    tier: 'rule',
    timeSemantics: 'snapshot',
    labelValues: ['家庭型', '社交型'],
    dataSource: 'DW fact_client_out.recommend_num/recommend_amount(DW 预聚合推荐人数+转化额)+ PatientRelation;未来宿主 CDP social_relations + settlement_records 逐人核',
    dataFields: ['recommend_num', 'recommend_amount', 'social_relations'],
    meaning: '识别有推荐能力且带来实质转化的客户;家庭型(带家人)推家庭套餐,社交型(推外人)给推荐奖励',
    algorithm: [
      '门槛:recommend_num ≥3 且 recommend_amount > 0(实质转化,v1 用 DW 聚合额作代理)。',
      '家庭型:直系家庭关系 ≥3(带家人);否则 社交型(推外人)。不满足→不打标签。',
      '⚠️ v1 用 DW 预聚合(逐个被推荐人"均有效转化"需其结算,跨患者+需被推荐人已摄入,留 v2)。',
    ].join('\n'),
    owner: 'pac-algo',
    version: 1,
  },

  // ── B.1.3 权益身份(业务 CDP 口径;多标签)──
  entitlement_status: {
    key: 'entitlement_status',
    nameZh: '权益身份',
    tier: 'rule',
    timeSemantics: 'lifetime', // 遍历历史全部结算记录
    labelValues: ['高端保险直付', '银行私行权益', '储值会员', '儿牙会员', '医保客户'],
    dataSource: 'DW fact_settlement_mode_out 卡券名(card_type_name/card_name)+ insurance_name/channel → payment_record.content;recharge_record(储值)',
    dataFields: ['settlement_records(卡券名称、权益类型)'],
    meaning: '通过历史结算卡券反推权益身份,识别高净值客户、预付费会员及医保覆盖客户',
    algorithm: [
      '遍历历史结算,命中关键词即打标(允许并列):',
      '高端保险直付 Bupa/中间带/保险直付/商保;银行私行 招行私行/私人银行/白金卡/贵宾卡;',
      '储值会员 储值/预存(或有充值);儿牙会员 儿牙会员/乐牙卡/涂氟年卡;医保 医保。未命中→不打标签。',
    ].join('\n'),
    owner: 'pac-algo',
    version: 2,
  },
};
