import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import {
  mergeMappingMisses,
  type MappingMiss,
} 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; runsWithMisses: number; distinct: number; misses: MappingMiss[] }> {
    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 lists: MappingMiss[][] = [];
    for (const l of logs) {
      const md = l.metadata as { mappingMisses?: MappingMiss[] } | null;
      if (md?.mappingMisses?.length) lists.push(md.mappingMisses);
    }
    const misses = mergeMappingMisses(lists);
    return {
      scannedRuns: logs.length,
      runsWithMisses: lists.length,
      distinct: misses.length,
      misses,
    };
  }
}
