import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import {
  mergeMappingMisses,
  mergeSuspectFields,
  type MappingMiss,
  type SuspectField,
} from '../sync/assembler/assembler-engine';
import type { TenantScopeContext } from '../../common/decorators/tenant-scope.decorator';

/**
 * MappingMissService — 映射覆盖漏审计。
 *
 * 数据来源:摄入(cold-import / push / reparse)时 assembler 把"enum_mapping 精确 + keyword
 * 都没命中、落到 _default"的原值聚合写进 SyncLog.metadata.mappingMisses。本服务扫最近 N 次
 * sync run 的 metadata 合并计数 → 给运维"看还有哪些原值没映射上"(如诊断名长尾)→ 扩字典 → reparse。
 *
 * 注:落 _default 既包含"故意不映射"(如 乳牙列 正常态)也包含"真漏"(如 松动牙);本接口只负责
 * 可见化,人工区分。
 */
@Injectable()
export class MappingMissService {
  constructor(private readonly prisma: PrismaService) {}

  async recent(
    scope: TenantScopeContext,
    opts: { limit?: number },
  ): Promise<{
    scannedRuns: number;
    runsWithDrift: number;
    misses: MappingMiss[];
    suspectFields: SuspectField[];
  }> {
    const take = Math.min(Math.max(opts.limit ?? 100, 1), 500);
    const logs = await this.prisma.syncLog.findMany({
      where: { hostId: scope.hostId },
      orderBy: { startedAt: 'desc' },
      take,
      select: { metadata: true },
    });
    const missLists: MappingMiss[][] = [];
    const suspectLists: SuspectField[][] = [];
    let runsWithDrift = 0;
    for (const l of logs) {
      const md = l.metadata as
        | { mappingMisses?: MappingMiss[]; suspectFields?: SuspectField[] }
        | null;
      let hit = false;
      if (md?.mappingMisses?.length) {
        missLists.push(md.mappingMisses);
        hit = true;
      }
      if (md?.suspectFields?.length) {
        suspectLists.push(md.suspectFields);
        hit = true;
      }
      if (hit) runsWithDrift++;
    }
    return {
      scannedRuns: logs.length,
      runsWithDrift,
      misses: mergeMappingMisses(missLists),
      suspectFields: mergeSuspectFields(suspectLists),
    };
  }
}
