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 也不会变,省一次
    // 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: r.status === 'success' || r.status === 'noop',
      personaId: r.personaId ?? null,
      status: r.status,
      planEnqueued,
    };
  }
}
