import { Injectable } from '@nestjs/common';
import { PersonaFeatureKey, FactType, FactKind } from '@pac/types';
import type {
  ActiveFact,
  FeatureExtractor,
  FeatureExtractorContext,
  PersonaFeatureDraft,
} from './feature.interface';
import { ageYearsAt, classifyGapToLabel } from './potential-treatment.feature';

/**
 * urgency_level 急迫等级(C.2.1)— 规则层,snapshot · 单一标签(取最大)
 *
 * 标签:紧急 / 高 / 中 / 低。客户当前所有待处理事项中**最高**的急迫程度,决定外呼优先级。
 *
 * ⚠️ v1 只做【潜在治疗路径】(用户口径:已治疗复查路径召回未实现该场景,先不做)。
 *   潜在治疗路径(复用 ctx.potentialGaps = 潜在待转):
 *     末诊 > 90 天  → 紧急(有未满足需求且久未回诊,正在流失)
 *     末诊 30-90 天 → 高
 *     末诊 < 30 天 或 新发现 → 中(刚来过/刚发现,还在跟进中)
 *     美学/预防性建议 → 低(当前 8 标签不含美学/预防 → 暂不触发)
 *   无潜在治疗 → 不打标签(无待处理事项,此路径无急迫)。
 *
 * 末诊口径同 lifecycle_stage(单一源):max occurredAt of encounter / actual treatment / 挂号。
 * Step 2 取最大:多路径时 MAX;现仅 1 路径。已治疗复查路径 = follow-up(待召回实现复查场景)。
 */
@Injectable()
export class UrgencyLevelFeatureExtractor implements FeatureExtractor {
  readonly key = PersonaFeatureKey.URGENCY_LEVEL;
  private static readonly DAY = 86400_000;

  extract(ctx: FeatureExtractorContext): PersonaFeatureDraft | null {
    // 潜在待转 = 映射到 8 业务标签的 gap(与 potential_treatment 同一源,口径一致;
    //   K00/K09/年龄外的 gap 不算"潜在治疗路径"待处理项 → 不计急迫)。
    const age = ageYearsAt(ctx.patient.birthDate, ctx.now);
    const labelKeys = new Set<string>();
    for (const g of ctx.potentialGaps ?? []) {
      const lbl = classifyGapToLabel(g, age);
      if (lbl) labelKeys.add(lbl.key);
    }
    if (labelKeys.size === 0) return null; // 无潜在待转(8 标签)→ 此路径无急迫
    const gaps = ctx.potentialGaps ?? [];

    // 末诊(末次就诊)— 口径同 lifecycle_stage
    const get = (t: string) => ctx.factsByType.get(t) ?? [];
    const visitFacts: ActiveFact[] = [
      ...get(FactType.ENCOUNTER_RECORD),
      ...get(FactType.TREATMENT_RECORD).filter((f) => f.kind === FactKind.ACTUAL),
      ...get(FactType.VISIT_REGISTRATION_RECORD),
    ];
    let last: number | null = null;
    for (const f of visitFacts) {
      if (!f.occurredAt) continue;
      const t = f.occurredAt.getTime();
      if (last === null || t > last) last = t;
    }
    const now = ctx.now.getTime();
    // 无就诊记录(罕见,有诊断必有诊)→ 回退用 gap 最早诊断天数
    const lastDays =
      last !== null
        ? Math.floor((now - last) / UrgencyLevelFeatureExtractor.DAY)
        : Math.max(...gaps.map((g) => g.daysSince));

    let code: string;
    let zh: string;
    if (lastDays > 90) {
      code = 'urgent';
      zh = '紧急';
    } else if (lastDays >= 30) {
      code = 'high';
      zh = '高';
    } else {
      code = 'mid';
      zh = '中';
    }

    const pendingLabels = labelKeys.size;
    return {
      key: this.key,
      description: `${zh} · 末诊${lastDays}天 · ${pendingLabels} 类潜在治疗`,
      score: null,
      data: { level: code, levelZh: zh, lastVisitDays: lastDays, pendingTypes: pendingLabels, path: 'potential_treatment' },
      evidence: { factIds: [] },
    };
  }
}
