import { Injectable, OnModuleInit } from '@nestjs/common';
import { CloudEvent, IIOS_EVENTS } from '@insignia/iios-contracts';
import { PrismaService } from '../prisma/prisma.service';
import { OutboxBus } from './outbox.bus';
import { DlqService } from './dlq.service';

/**
 * Dev-only chaos consumer (P9). Drives the DLQ smoke deterministically: it THROWS on
 * the first delivery of a chaos event (so the event is dead-lettered) and SUCCEEDS on
 * replay (so the DLQ item resolves). Registered like any projector — same claim() +
 * onConsumerFailure wiring — so it exercises the real dead-letter/replay path.
 */
@Injectable()
export class ChaosConsumer implements OnModuleInit {
  private readonly consumer = 'chaos-consumer';
  private readonly seen = new Set<string>();

  constructor(
    private readonly prisma: PrismaService,
    private readonly bus: OutboxBus,
    private readonly dlq: DlqService,
  ) {}

  onModuleInit(): void {
    this.dlq.registerHandler(this.consumer, (e) => this.onChaos(e));
    this.bus.on(IIOS_EVENTS.devChaos, (p) => void this.onChaos(p as CloudEvent).catch((err) => this.dlq.onConsumerFailure(this.consumer, p as CloudEvent, err)));
  }

  async onChaos(event: CloudEvent): Promise<void> {
    if (!(await this.claim(event.id))) return; // idempotent
    if (!this.seen.has(event.id)) {
      this.seen.add(event.id);
      throw new Error('chaos: first delivery always fails'); // → dead-lettered, claim cleared
    }
    // replay: succeeds (the claim persists, marking it processed exactly-once)
  }

  private async claim(eventId: string): Promise<boolean> {
    const res = await this.prisma.iiosProcessedEvent.createMany({
      data: [{ consumerName: this.consumer, eventId }],
      skipDuplicates: true,
    });
    return res.count > 0;
  }
}
