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

/**
 * contraindication 禁忌标签(D.2.4)— 规则层,snapshot · 多标签
 *
 * 标签:种植禁忌 / 正畸禁忌 / 麻醉禁忌 / 手术禁忌(治疗可行性 + 安全预警)。
 *
 * ⚠️ v1 只实现【种植年龄禁忌:年龄≤18(骨骼发育未完全)】—— 这是唯一可用确定性规则可靠判定的。
 *   其余禁忌(糖尿病/高血压/过敏/抗凝/妊娠/放疗…)依赖既往史自由文本,而:
 *     ① 否定问题:含"过敏"的既往史 97% 是"否认过敏"——naive 关键词会把无过敏标成麻醉禁忌(医疗事故);
 *     ② 量化条件无数据:HbA1c(全量仅10条)/收缩压 无法判"控制不佳",分不清能否种植;
 *     ③ 需控制状态/急性期判断 + 时效窗口。
 *   → 这些是 Layer C(LLM 抽取:读既往史、处理否定、判控制/急性)的活,留 W5+。本特征 data 结构
 *     已留多标签位,Layer C 就绪后并入(同一 key,补 types)。
 *
 * 时效:年龄禁忌随年龄自动解除(满 19 岁后重算即不打);validUntil 标注到期日(满 19 岁)。
 */
@Injectable()
export class ContraindicationFeatureExtractor implements FeatureExtractor {
  readonly key = PersonaFeatureKey.CONTRAINDICATION;
  private static readonly IMPLANT_MIN_AGE = 19; // ≤18 禁忌 → 满 19 解除

  private static ageYears(birth: Date, now: Date): number {
    let age = now.getFullYear() - birth.getFullYear();
    const m = now.getMonth() - birth.getMonth();
    if (m < 0 || (m === 0 && now.getDate() < birth.getDate())) age--;
    return age;
  }

  extract(ctx: FeatureExtractorContext): PersonaFeatureDraft | null {
    const birth = ctx.patient.birthDate;
    if (!birth) return null;
    const age = ContraindicationFeatureExtractor.ageYears(birth, ctx.now);
    if (age < 0 || age > 120) return null;

    const types: Array<{ code: string; zh: string; reason: string; validUntil: string | null }> = [];
    // 种植年龄禁忌:≤18 岁
    if (age <= 18) {
      const lift = new Date(birth);
      lift.setFullYear(lift.getFullYear() + ContraindicationFeatureExtractor.IMPLANT_MIN_AGE);
      types.push({
        code: 'implant_age',
        zh: '种植禁忌',
        reason: `年龄${age}岁(骨骼发育未完全)`,
        validUntil: lift.toISOString().slice(0, 10),
      });
    }
    // 其余禁忌(糖尿病/过敏/抗凝/妊娠…)留 Layer C —— 见类注释

    if (types.length === 0) return null;
    return {
      key: this.key,
      description: types.map((t) => `${t.zh}(${t.reason})`).join(' / '),
      score: null,
      data: { types: types.map((t) => t.code), labels: types.map((t) => t.zh), detail: types },
      evidence: { factIds: [] }, // v1 证据=patient.birthDate(年龄禁忌,非 fact)
    };
  }
}
