import { Injectable, Logger } from '@nestjs/common';
import { InjectQueue } from '@nestjs/bullmq';
import type { Queue } from 'bullmq';
import { QueueName, QueueDefaults } from './queue-names';
import type {
  PersonaRecomputeJob,
  PlanRecomputeJob,
  PlanAssetGenerateJob,
} from './job-payloads';

/**
 * QueueProducer — 给业务模块(sync / persona / plan)统一的入队接口。
 *
 * 设计点:
 *   - `jobName` 是 BullMQ 的去重 / 串行键 ⭐
 *     · persona / plan recompute  → jobName = patientId(同 patient 串行)
 *     · plan-asset-generate       → jobName = planId(同 plan 串行)
 *   - 同 jobName 在队列里只保留 1 个 waiting 的 job(用 deduplication)
 *     防止 1 秒内来 10 个 txn 队列里堆 10 个重复 job
 *   - 失败重试 / 退避 由 QueueDefaults 统一管理,模块不自定义
 */
@Injectable()
export class QueueProducer {
  private readonly logger = new Logger(QueueProducer.name);

  constructor(
    @InjectQueue(QueueName.PERSONA_RECOMPUTE) private readonly personaQ: Queue,
    @InjectQueue(QueueName.PLAN_RECOMPUTE) private readonly planQ: Queue,
    @InjectQueue(QueueName.PLAN_ASSET_GENERATE) private readonly assetQ: Queue,
  ) {}

  async enqueuePersonaRecompute(job: PersonaRecomputeJob): Promise<void> {
    // jobId 用 _ 分隔(BullMQ 不允许 :);同 patient 的 waiting job 自动去重
    await this.personaQ.add(job.patientId, job, {
      jobId: `persona_${job.patientId}`,
      ...QueueDefaults[QueueName.PERSONA_RECOMPUTE],
    });
    this.logger.debug(
      `enqueue persona-recompute patient=${job.patientId} triggeredBy=${job.triggeredBy}`,
    );
  }

  async enqueuePlanRecompute(job: PlanRecomputeJob): Promise<void> {
    await this.planQ.add(job.patientId, job, {
      jobId: `plan_${job.patientId}`,
      ...QueueDefaults[QueueName.PLAN_RECOMPUTE],
    });
    this.logger.debug(
      `enqueue plan-recompute patient=${job.patientId} triggeredBy=${job.triggeredBy}`,
    );
  }

  async enqueuePlanAssetGenerate(job: PlanAssetGenerateJob): Promise<void> {
    await this.assetQ.add(job.planId, job, {
      jobId: `asset_${job.planId}`,
      ...QueueDefaults[QueueName.PLAN_ASSET_GENERATE],
    });
    this.logger.debug(
      `enqueue plan-asset-generate plan=${job.planId.slice(0, 8)} triggeredBy=${job.triggeredBy}`,
    );
  }
}
