import { Injectable, Logger } from '@nestjs/common';
import {
  Action,
  FactKind,
  FactStatus,
  FactType,
  PACDiagnosisCodeSchema,
} from '@pac/types';
import type { Parser, ParserContext, FactDraft } from './parser.interface';
import { normalizeToothPosition } from './tooth-position.util';

/**
 * RecommendationParser — `recommendation_extracted` 解析器(v2.1 新)
 *
 * 处理"医生建议 / 推荐治疗"信号:
 *   - Layer C LLM 抽取产物(extractedBy='llm',W3+ AiCall 接入)
 *   - 规则识别(extractedBy='rule',关键词匹配 EMR 文本,兜底)
 *   - 医生显式录入(extractedBy='doctor_input',host 结构化字段)
 *
 * **本 parser 不实现 LLM 抽取**(那是 Layer C signal-extractor 的活);
 * 仅消费已经过 Layer A yaml 翻译好的 canonical recommendation row,直接生成独立 fact。
 *
 * **必填**:`code` ∈ PAC 推荐码(IMPLANT_RECOMMENDED / CROWN_RECOMMENDED 等)。
 */
@Injectable()
export class RecommendationParser implements Parser {
  readonly name = Action.RECOMMENDATION_EXTRACTED;
  private readonly logger = new Logger(RecommendationParser.name);

  parse(ctx: ParserContext): FactDraft[] {
    const c = ctx.canonicalRow;
    const externalId = String(c.externalId ?? ctx.transaction.subjectId).trim();
    if (!externalId) {
      this.logger.warn(
        `recommendation parser: missing externalId tx=${ctx.transaction.id};skip`,
      );
      return [];
    }

    // code 命中白名单 → canonical 推荐码(触发召回);未命中 → null(长尾建议,仅病历展示)
    const rawCode = String(c.code ?? '').trim();
    const codeParsed = PACDiagnosisCodeSchema.safeParse(rawCode);
    const code = codeParsed.success ? codeParsed.data : null;
    // 医生原文(如"建议更换")— 忠实展示;选 A:长尾建议也保留(不再 drop)
    const name = String(c.name ?? '').trim() || null;
    if (!code && !name) {
      // 既无 canonical 码、又无原文 → 无可展示内容,跳过
      return [];
    }

    const extractedBy = (c.extractedBy as string | undefined) ?? 'rule';
    const confidence =
      typeof c.confidence === 'number'
        ? c.confidence
        : c.confidence
          ? Number(c.confidence)
          : null;

    return [
      {
        subjectId: `${FactType.RECOMMENDATION_RECORD}:${externalId}`,
        kind: FactKind.PLANNED, // 建议本质是"未来该做的事"
        type: FactType.RECOMMENDATION_RECORD,
        status: FactStatus.ACTIVE,
        clinicId: ctx.transaction.clinicId,
        plannedFor: ctx.transaction.occurredAt,
        title: name ? `建议:${name}` : `建议 ${code}`,
        summary: null,
        content: {
          code,
          name,
          source_encounter_external_id:
            (c.sourceEncounterExternalId as string | undefined) ?? null,
          tooth_position: normalizeToothPosition(c.toothPosition as string | undefined),
          doctor_id: c.doctorId ? String(c.doctorId) : null,
          doctor_name: (c.doctorName as string | undefined) ?? null,
          extracted_by: extractedBy,
          confidence,
          source_fact_subject_id:
            (c.sourceFactSubjectId as string | undefined) ?? null,
          doctor_suggested_at: ctx.transaction.occurredAt.toISOString(),
          window_days:
            typeof c.windowDays === 'number'
              ? c.windowDays
              : c.windowDays
                ? Number(c.windowDays)
                : null,
        },
      },
    ];
  }
}
