import { Injectable } from '@nestjs/common';
import { PersonaFeatureKey } from '@pac/types';
import type {
  ActiveFact,
  FeatureExtractor,
  FeatureExtractorContext,
  PersonaFeatureDraft,
} from './feature.interface';

/**
 * entitlement_status 权益身份(B.1.3)— 规则层,snapshot · 多标签(允许并列)
 *
 * 口径(图):遍历历史结算记录,命中关键词即打标(可多类并列);未命中→不打标签。
 *   数据源:payment_record.content 的 card_type_name / card_name / insurance_name / channel
 *     (摄入自 fact_settlement_mode_out 卡券字段)+ recharge_record(储值)。
 *   5 类:
 *     高端保险直付:Bupa / 中间带 / 保险直付 / 商保(或 channel=insurance / 有保司名)
 *     银行私行权益:招行私行 / 私人银行 / 白金卡 / 贵宾卡 / 私行
 *     储值会员:    储值 / 预存(或有 recharge_record 充值)
 *     儿牙会员:    儿牙会员 / 乐牙卡 / 涂氟年卡 / 儿牙 / 乐牙
 *     医保客户:    医保(或 channel=medical_insurance)
 */
@Injectable()
export class EntitlementStatusFeatureExtractor implements FeatureExtractor {
  readonly key = PersonaFeatureKey.ENTITLEMENT_STATUS;

  // 关键词集(命中卡券/保司文本即打标)
  private static readonly RULES: Array<{ code: string; zh: string; kw: string[] }> = [
    { code: 'high_insurance', zh: '高端保险直付', kw: ['bupa', '中间带', '保险直付', '商保', '万欣和', '招商信诺', 'msh'] },
    { code: 'bank_vip', zh: '银行私行权益', kw: ['招行私行', '私人银行', '白金卡', '贵宾卡', '私行'] },
    { code: 'stored_value', zh: '储值会员', kw: ['储值', '预存'] },
    { code: 'pedo_member', zh: '儿牙会员', kw: ['儿牙会员', '乐牙卡', '涂氟年卡', '儿牙', '乐牙'] },
    { code: 'medical', zh: '医保客户', kw: ['医保'] },
  ];

  extract(ctx: FeatureExtractorContext): PersonaFeatureDraft | null {
    const payments = (ctx.factsByType.get('payment_record') ?? []) as ActiveFact[];
    const hasRecharge = (ctx.factsByType.get('recharge_record') ?? []).length > 0;

    const matched = new Set<string>();
    const evidenceIds = new Set<string>();

    for (const f of payments) {
      const c = (f.content ?? {}) as Record<string, unknown>;
      const channel = String(c.channel ?? '');
      const text = [c.card_type_name, c.card_name, c.insurance_name]
        .map((x) => String(x ?? ''))
        .join(' ')
        .toLowerCase();
      let hit = false;
      // channel 强信号
      if (channel === 'insurance' || String(c.insurance_name ?? '').trim()) {
        matched.add('high_insurance');
        hit = true;
      }
      if (channel === 'medical_insurance') {
        matched.add('medical');
        hit = true;
      }
      // 卡券/保司关键词
      for (const r of EntitlementStatusFeatureExtractor.RULES) {
        if (r.kw.some((k) => text.includes(k.toLowerCase()))) {
          matched.add(r.code);
          hit = true;
        }
      }
      if (hit) evidenceIds.add(f.id);
    }

    // 储值:有充值记录也算
    if (hasRecharge) matched.add('stored_value');

    if (matched.size === 0) return null; // 未命中 → 不打标签

    // 按 RULES 顺序输出(稳定)
    const ordered = EntitlementStatusFeatureExtractor.RULES.filter((r) => matched.has(r.code));
    const codes = ordered.map((r) => r.code);
    const labels = ordered.map((r) => r.zh);

    return {
      key: this.key,
      description: labels.join(' / '),
      score: null,
      data: { types: codes, labels },
      evidence: { factIds: [...evidenceIds] },
    };
  }
}
