import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { PrismaService } from '../prisma/prisma.service';
import { AlertService } from '../common/alerting/alert.service';

/**
 * DwLagMonitorService — 每小时检查 DW 增量数据滞后(W4 末)
 *
 * 输入:sync_logs 中最近一条成功的 incremental_bundle 的 cursor_after JSON
 *       例:{"fact_emr_treatment_out":"2026-05-26 15:30:00",...}
 *
 * 计算:max(cursor_after.*) vs now() → diff hours
 *   - diff <= 24h:🟢 健康
 *   - 24h < diff <= 48h:🟡 注意(DW 可能没刷新,提醒值班)
 *   - diff > 48h:🔴 异常(数据严重滞后,事件可能漏召)
 *
 * 当前实现:log + (TODO) 接 webhook/email/钉钉。
 *
 * 调整阈值:PAC_LAG_WARN_HOURS=24 / PAC_LAG_ERROR_HOURS=48 env
 */
@Injectable()
export class DwLagMonitorService {
  private readonly logger = new Logger(DwLagMonitorService.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly alerter: AlertService,
  ) {}

  /// DW 数据滞后告警 cron — env 驱动
  /// PAC_LAG_MONITOR_CRON:
  ///   不设         → 不跑(local 默认)
  ///   '0 * * * *'  → 生产 / staging 推荐(每小时检查)
  @Cron(process.env.PAC_LAG_MONITOR_CRON || '0 0 31 12 *' /* never — env not set */, {
    name: 'dw-lag-monitor',
  })
  async checkLag(): Promise<void> {
    const warnH = Number(process.env.PAC_LAG_WARN_HOURS ?? '24');
    const errorH = Number(process.env.PAC_LAG_ERROR_HOURS ?? '48');
    const now = Date.now();

    const hosts = await this.prisma.host.findMany({ select: { id: true, name: true } });
    for (const host of hosts) {
      const last = await this.prisma.syncLog.findFirst({
        where: {
          hostId: host.id,
          resource: 'incremental_bundle',
          status: 'success',
          cursorAfter: { not: null },
        },
        orderBy: { startedAt: 'desc' },
      });
      if (!last?.cursorAfter) {
        this.logger.warn(`dw-lag: host=${host.name} 还没跑过增量(无 cursor)— 检查 sync-incremental cron`);
        continue;
      }
      let cursors: Record<string, string>;
      try {
        cursors = JSON.parse(last.cursorAfter) as Record<string, string>;
      } catch {
        this.logger.warn(`dw-lag: host=${host.name} cursor JSON 解析失败 — ${last.cursorAfter}`);
        continue;
      }
      const maxCursorTs = Math.max(
        ...Object.values(cursors)
          .map((v) => new Date(v).getTime())
          .filter((t) => !isNaN(t)),
      );
      const diffHours = (now - maxCursorTs) / 3_600_000;
      const tag =
        diffHours > errorH ? '🔴' :
        diffHours > warnH ? '🟡' :
        '🟢';
      const msg = `dw-lag: ${tag} host=${host.name} max_cursor=${new Date(maxCursorTs).toISOString()} lag=${diffHours.toFixed(1)}h (warn=${warnH} error=${errorH})`;
      if (diffHours > errorH) {
        this.logger.error(msg);
        await this.alerter.send({
          level: 'critical',
          title: 'DW 数据严重滞后',
          body: `增量游标已 ${diffHours.toFixed(1)} 小时未推进(阈值 ${errorH}h)— 事件可能漏召。`,
          context: { host: host.name, maxCursor: new Date(maxCursorTs).toISOString() },
        });
      } else if (diffHours > warnH) {
        this.logger.warn(msg);
        await this.alerter.send({
          level: 'warning',
          title: 'DW 数据滞后(注意)',
          body: `增量游标已 ${diffHours.toFixed(1)} 小时未推进(阈值 ${warnH}h)— DW 可能没刷新。`,
          context: { host: host.name, maxCursor: new Date(maxCursorTs).toISOString() },
        });
      } else {
        this.logger.log(msg);
      }
    }
  }
}
