import { Injectable } from '@nestjs/common';
import { PersonaFeatureKey } from '@pac/types';
import type {
  FeatureExtractor,
  FeatureExtractorContext,
  PersonaFeatureDraft,
} from './feature.interface';
import { nextAgeBoundary } from './time-boundary';
import { ageYearsAt } from './potential-treatment.feature';

/**
 * age_bracket 年龄段(A.1.1)— 规则层,snapshot 时间语义(当下从 birthDate 算)
 *
 * 口径采用业务整理好的 CDP 标签定义:
 *   数据字段:client_age(Int32)— 现从 PAC patient.birthDate 自算;宿主 CDP 给 client_age 后切宿主值
 *   标签释义:按口腔治疗需求特征精细划分年龄层,匹配适龄项目与家庭决策模式
 *   区间规则(图):0-3 婴幼儿 / 3-6 学龄前 / 7-11 替牙期 / 12-17 青少年 / 18-25 青年 /
 *                 26-30 中青年 / 31-45 中年 / 46-55 中老年 / ≥55 老年
 *   ⚠️ 图区间在 3 / 55 两点重叠:按"下界含、上界归下一档"消歧,且 ≥55→老年(终值规则)优先:
 *      → 婴幼儿 0-2 / 学龄前 3-6 / 替牙期 7-11 / 青少年 12-17 / 青年 18-25 / 中青年 26-30 /
 *        中年 31-45 / 中老年 46-54 / 老年 ≥55
 *
 * snapshot:每次重算按当下年龄取值(年龄随时间增长,看历史年龄读 persona 版本流)。
 * birthDate 缺失 / 年龄越界(<0 或 >120,脏数据)→ 不打标签(返回 null)。
 */
@Injectable()
export class AgeBracketFeatureExtractor implements FeatureExtractor {
  readonly key = PersonaFeatureKey.AGE_BRACKET;

  // 下界含,顺序匹配第一个 age < 下一档下界的档(老年为兜底)
  private static readonly BRACKETS: Array<{ min: number; code: string; zh: string }> = [
    { min: 0, code: 'infant', zh: '婴幼儿' }, // 0-2
    { min: 3, code: 'preschool', zh: '学龄前' }, // 3-6
    { min: 7, code: 'mixed_dentition', zh: '替牙期' }, // 7-11
    { min: 12, code: 'adolescent', zh: '青少年' }, // 12-17
    { min: 18, code: 'youth', zh: '青年' }, // 18-25
    { min: 26, code: 'young_adult', zh: '中青年' }, // 26-30
    { min: 31, code: 'middle_aged', zh: '中年' }, // 31-45
    { min: 46, code: 'pre_senior', zh: '中老年' }, // 46-54
    { min: 55, code: 'senior', zh: '老年' }, // ≥55
  ];

  extract(ctx: FeatureExtractorContext): PersonaFeatureDraft | null {
    const birth = ctx.patient.birthDate;
    if (!birth) return null; // 无出生日期 → 不打标签
    const age = ageYearsAt(birth, ctx.now);
    if (age === null || age < 0 || age > 120) return null; // 脏数据

    // 取最后一个 min ≤ age 的档(BRACKETS 升序)
    let bracket = AgeBracketFeatureExtractor.BRACKETS[0]!;
    for (const b of AgeBracketFeatureExtractor.BRACKETS) {
      if (age >= b.min) bracket = b;
      else break;
    }

    return {
      key: this.key,
      description: `${bracket.zh} · ${age}岁`,
      score: null, // 弃用语义,场景从 data 取
      data: {
        bracket: bracket.code, // 圈人群/筛选用稳定 code
        label: bracket.zh,
        ageYears: age,
      },
      // 年龄来自 patient 主档 birthDate(非 fact),无 fact 证据
      evidence: { factIds: [] }, // 证据=patient.birthDate(主档,非 fact)
    };
  }

  /**
   * 下一次跨档 = 满下一个档位下界的那个生日。
   *
   * ⚠️ 本特征**完全不依赖 fact**,所以没有这个边界它就永远不会被重算 —— 一个 54 岁患者
   * 会一直显示「中老年」直到他碰巧有新事实进来。年龄还喂着按龄排治疗(>70 优先活动义齿)。
   */
  nextBoundaryAt(ctx: FeatureExtractorContext): Date | null {
    return nextAgeBoundary(
      ctx.patient.birthDate,
      ctx.now,
      AgeBracketFeatureExtractor.BRACKETS.map((b) => b.min),
    );
  }
}
