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

/**
 * RecycleSchedulerService — 召回工单超时自动回收(GAP3 闭环)
 *
 * 背景:assign 时锁定 recycleAt = assignedAt + RECYCLE_TIMEOUT_HOURS(默认 24h)。
 *   旧实现只写了 deadline 却**没有任何 cron 执行回收** —— 客服领了工单去休假 / 漏跟,
 *   plan 永远停在 assigned,plan 引擎 upsert 时 `skipped_assigned` 永久跳过,
 *   这个患者既不会被别人捡走、也不会更新。本服务补上自动回收。
 *
 * 行为:每 10 分钟扫一遍,把"已分配 + 已过 recycleAt"的 plan 退回召回池:
 *   status: assigned → active;清空 assignee / assignedAt / recycleAt。
 *   用 updateMany 一条 SQL 批量处理(无需逐行),幂等、并发安全。
 *
 * 注:手动回收(POST /plans/{id}/recycle)仍保留,本 cron 只兜底超时未结案的。
 */
@Injectable()
export class RecycleSchedulerService {
  private readonly logger = new Logger(RecycleSchedulerService.name);

  constructor(private readonly prisma: PrismaService) {}

  @Cron(CronExpression.EVERY_10_MINUTES, { name: 'plan-recycle-stale' })
  async runRecycle(): Promise<void> {
    const now = new Date();
    const r = await this.prisma.followupPlan.updateMany({
      where: {
        status: 'assigned',
        recycleAt: { not: null, lt: now },
        // ⭐ 跳过仍在冷静期/约定回访中的 plan(snoozedUntil 在未来)。
        //   场景:客服约了 6/10 回访,plan snooze 到 6/10;在那之前**不能**因 24h 超时被回收,
        //   否则客服丢了已承诺的回访关系、6/10 一到还会被别人从池里捞走。
        //   回访日过后(snoozedUntil<=now)若仍未处理,才允许回收。
        OR: [{ snoozedUntil: null }, { snoozedUntil: { lte: now } }],
      },
      data: {
        status: 'active',
        assigneeUserId: null,
        assignedAt: null,
        recycleAt: null,
      },
    });
    if (r.count > 0) {
      this.logger.log(`auto-recycle: ${r.count} 个超时未结案工单退回召回池`);
    }
  }
}
