import { Logger } from '@nestjs/common';
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Job } from 'bullmq';
import { QueueName } from '../queue-names';
import type { PlanRecomputeJob } from '../job-payloads';
import { QueueProducer } from '../queue-producer.service';
import { PlanEngineService } from '../../modules/plan/engine/plan-engine.service';
import { PrismaService } from '../../prisma/prisma.service';

/**
 * plan-recompute worker
 *
 * 触发链:
 *   persona-recompute 完(success/partial)→ enqueue (jobName=patientId)
 *   plan 写入后 → 逐条 enqueue plan-asset-generate(Commit 5 接,但目前 stub 不烧 token)
 *
 * ⚠️ PlanEngine 当前是 host-wide(W2 兼容);本 processor 通过"按时间窗反查"找到本批新/改的 plan。
 */
@Processor(QueueName.PLAN_RECOMPUTE, { concurrency: 4 })
export class PlanRecomputeProcessor extends WorkerHost {
  private readonly logger = new Logger(PlanRecomputeProcessor.name);

  constructor(
    private readonly engine: PlanEngineService,
    private readonly queue: QueueProducer,
    private readonly prisma: PrismaService,
  ) {
    super();
  }

  async process(job: Job<PlanRecomputeJob>): Promise<{
    ok: boolean;
    plansCreated: number;
    assetsEnqueued: number;
  }> {
    const { hostId, tenantId, patientId, clinicId, triggeredBy } = job.data;
    const startedAt = new Date();
    this.logger.log(
      `plan-recompute START patient=${patientId} triggeredBy=${triggeredBy} attempts=${job.attemptsMade + 1}`,
    );

    await this.engine.recomputeForPatient({
      hostId,
      tenantId,
      clinicId: clinicId ?? '',
      patientId,
    });

    // ─── 找本次受影响的 plan(本 patient,且 updatedAt 在 recompute 开始之后)───
    // 因 PlanEngine 当前 host-wide 跑全量,这种"反查"是最简单的归因方式。
    // W3+ PlanEngine 改造为真正 per-patient 后,可以让 engine 直接返回 affectedPlanIds。
    const affected = await this.prisma.followupPlan.findMany({
      where: {
        hostId,
        tenantId,
        patientId,
        status: { in: ['active', 'assigned'] },
        updatedAt: { gte: startedAt },
      },
      select: { id: true },
    });

    this.logger.log(
      `plan-recompute DONE patient=${patientId} affectedPlans=${affected.length}`,
    );

    // ─── 链式触发 plan-asset-generate ───
    // 注:asset processor 当前是 stub(不调 AI,省 token);
    // 真实生成靠详情页的"重新生成"按钮调 POST :id/script:regenerate
    let assetsEnqueued = 0;
    for (const p of affected) {
      try {
        await this.queue.enqueuePlanAssetGenerate({
          hostId,
          tenantId,
          planId: p.id,
          triggeredBy: `plan-recompute:${patientId}`,
        });
        assetsEnqueued++;
      } catch (err) {
        this.logger.warn(
          `enqueue plan-asset-generate failed plan=${p.id}: ${err instanceof Error ? err.message : err}`,
        );
      }
    }

    return { ok: true, plansCreated: affected.length, assetsEnqueued };
  }
}
