import { Injectable } from '@nestjs/common';
import { PersonaFeatureKey, FactType } from '@pac/types';
import {
  ChainComposerService,
  type ChainComposeInputFact,
} from '../../plan/engine/chain-composer.service';
import type {
  FeatureExtractor,
  FeatureExtractorContext,
  PersonaFeatureDraft,
} from './feature.interface';

/**
 * treatment_chain_status 治疗链状态(v2.2 — 复用 chain-composer,与治疗链面板/召回同口径)
 *
 * v2.2 重塑(修"画像缺口数 ≠ 召回缺口数"):
 *   旧版自己用**类别级**判定缺口(`actualByCat.has(cat)`)— 不看牙位/时间/替代闭环,
 *   会把"缺牙11(K08)被无关 prosthodontic 治疗掩盖"漏算 → 画像显示 1,实际 2。
 *   新版直接调 ChainComposerService.compose(facts)(就是画"治疗链面板"那套,已正确处理
 *   牙位分链 / 时间方向 / 替代闭环),数 status='discovered' 且非 alternativeClosedBy 的链 =
 *   "潜在新链 = 缺口",跟召回理由 / 治疗链面板逐条一致。
 *
 * 规则(v1 语义不变,判据换成 chain):
 *   - 无任何 chain（无诊断/治疗/建议） → 'no_chain'(从未进入)
 *   - 有 discovered 且非替代闭环的链     → 'gap'(链有缺口,召回核心信号)
 *   - 否则有 entered/ongoing 链          → 'in_progress'(在管)
 *   - 否则有 closed 链                   → 'closed'(已闭环)
 */
@Injectable()
export class TreatmentChainStatusFeatureExtractor implements FeatureExtractor {
  readonly key = PersonaFeatureKey.TREATMENT_CHAIN_STATUS;

  constructor(private readonly chainComposer: ChainComposerService) {}

  extract(ctx: FeatureExtractorContext): PersonaFeatureDraft | null {
    const diagnoses = ctx.factsByType.get(FactType.DIAGNOSIS_RECORD) ?? [];
    const treatments = ctx.factsByType.get(FactType.TREATMENT_RECORD) ?? [];
    const recommendations =
      ctx.factsByType.get(FactType.RECOMMENDATION_RECORD) ?? [];

    if (
      diagnoses.length === 0 &&
      treatments.length === 0 &&
      recommendations.length === 0
    ) {
      return {
        key: this.key,
        description: '从未进入治疗链(无诊断 / 治疗 / 建议记录)',
        score: 0,
        evidence: { factIds: [] },
      };
    }

    // 复用 chain-composer:它消费所有 active facts,内部按 type 分组
    const allFacts = [...ctx.factsByType.values()].flat() as ChainComposeInputFact[];
    const chains = this.chainComposer.compose(allFacts);

    // 缺口 = 潜在新链:discovered(仅 S1 命中)且未被替代方案闭环覆盖
    const gapChains = chains.filter(
      (c) => c.status === 'discovered' && !c.alternativeClosedBy,
    );
    const activeChains = chains.filter(
      (c) => c.status === 'entered' || c.status === 'ongoing',
    );
    const closedChains = chains.filter((c) => c.status === 'closed');

    // 证据:诊断 / 治疗 / 建议 fact ids(反查链路)
    const factIds = [
      ...diagnoses.map((f) => f.id),
      ...treatments.map((f) => f.id),
      ...recommendations.map((f) => f.id),
    ];

    let status: string;
    let description: string;
    let score: number;

    if (gapChains.length > 0) {
      status = 'gap';
      const names = gapChains.map((c) => c.name).slice(0, 3);
      const more = gapChains.length > 3 ? ` 等 ${gapChains.length} 处` : '';
      description = `${gapChains.length} 处缺口 — ${names.join('、')}${more}`;
      score = 3;
    } else if (activeChains.length > 0) {
      status = 'in_progress';
      description = `治疗链进行中(${activeChains.length} 条在管)`;
      score = 1;
    } else if (closedChains.length > 0) {
      status = 'closed';
      description = `治疗链已闭环(${closedChains.length} 条已完成)`;
      score = 2;
    } else {
      // 有信号但 chain 既非 gap 也非在管/闭环(罕见兜底)
      status = 'gap';
      description = '有诊断 / 建议,治疗链待跟进';
      score = 3;
    }

    return {
      key: this.key,
      description: `[${status}] ${description}`,
      score,
      evidence: { factIds },
    };
  }
}
