import { Logger } from '@nestjs/common';
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Job } from 'bullmq';
import { QueueName } from '../queue-names';
import type { PersonaRecomputeJob } from '../job-payloads';
import { QueueProducer } from '../queue-producer.service';
import { PersonaService } from '../../modules/persona/persona.service';

/**
 * persona-recompute worker
 *
 * 流程:
 *   1. 调 PersonaService.recompute() — 内部 eventWatermark 幂等(noop 短路)
 *   2. 成功(status=success/partial)→ 链式 enqueue plan-recompute
 *   3. noop / failed → 不向下游传播
 */
@Processor(QueueName.PERSONA_RECOMPUTE, { concurrency: 4 })
export class PersonaRecomputeProcessor extends WorkerHost {
  private readonly logger = new Logger(PersonaRecomputeProcessor.name);

  constructor(
    private readonly persona: PersonaService,
    private readonly queue: QueueProducer,
  ) {
    super();
  }

  async process(job: Job<PersonaRecomputeJob>): Promise<{
    ok: boolean;
    personaId: string | null;
    status: string;
    planEnqueued: boolean;
  }> {
    const { hostId, tenantId, patientId, triggeredBy } = job.data;
    this.logger.log(
      `persona-recompute START patient=${patientId} triggeredBy=${triggeredBy} attempts=${job.attemptsMade + 1}`,
    );

    const r = await this.persona.recompute({ patientId, source: triggeredBy });

    this.logger.log(
      `persona-recompute DONE patient=${patientId} status=${r.status} ` +
        `persona=${r.personaId ?? 'noop'} v${r.version} features=${r.featureCount} duration=${r.durationMs}ms`,
    );

    // 链式触发:只在画像**语义**确有更新时(success / partial)才下推 plan 重算。
    //   noop      水位幂等,压根没算 → plan 也不会变
    //   unchanged 算了但内容一字未变 → 同上
    //   refreshed 只有天数/年龄这类易变值变了 → 召回打分读的是 rfm.segment / urgency.level /
    //             lifecycle.stage 这些**分档**,分档没变就不必重排(变了会判成 semantic)
    //   failed    persona 写库挂了 → 不传播,等重试 / 死信
    let planEnqueued = false;
    if (r.status === 'success' || r.status === 'partial') {
      try {
        await this.queue.enqueuePlanRecompute({
          hostId,
          tenantId,
          patientId,
          triggeredBy: `persona:${r.version}`,
        });
        planEnqueued = true;
      } catch (err) {
        this.logger.warn(
          `enqueue plan-recompute failed patient=${patientId}: ${err instanceof Error ? err.message : err}`,
        );
      }
    }

    return {
      // ok = 干净完成。新增的 unchanged / refreshed 与 noop 同档(都属"无需升版本"的正常结果);
      // partial 仍不算 ok(有 extractor 抛错),沿用原语义。
      ok: r.status === 'success' || r.status === 'noop' || r.status === 'unchanged' || r.status === 'refreshed',
      personaId: r.personaId ?? null,
      status: r.status,
      planEnqueued,
    };
  }
}
