import { Processor, WorkerHost, OnWorkerEvent } from '@nestjs/bullmq';
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import type { Job } from 'bullmq';
import { AggregationService } from './aggregation.service';
import { RawEvent } from '../entities/raw-event.entity';

interface EventJob {
  eventId: string;
  eventType: string;
  sessionId: string;
}

@Injectable()
@Processor('analytics-events', {
  concurrency: 10,
})
export class EventsProcessor extends WorkerHost {
  private readonly logger = new Logger(EventsProcessor.name);

  constructor(
    private readonly aggregationService: AggregationService,
    @InjectRepository(RawEvent)
    private readonly rawEventRepository: Repository<RawEvent>,
  ) {
    super();
  }

  async process(job: Job<EventJob>): Promise<void> {
    const { eventId, eventType, sessionId } = job.data;

    this.logger.debug(`Processing event: ${eventType} (id: ${eventId}) from session ${sessionId}`);

    const event = await this.rawEventRepository.findOne({ where: { id: eventId } });

    if (!event) {
      this.logger.warn(`Event ${eventId} not found in raw_events — skipping`);
      return;
    }

    if (event.processed) {
      this.logger.debug(`Event ${eventId} already processed — skipping`);
      return;
    }

    await this.aggregationService.processEvent({
      eventType: event.eventType,
      timestamp: event.timestamp,
      sessionId: event.sessionId,
      userId: event.userId,
      properties: {
        ...(event.metadata ?? {}),
        path: event.pageUrl ?? undefined,
        deviceType: event.deviceType ?? undefined,
      },
    });

    await this.rawEventRepository.update(eventId, {
      processed: true,
      processedAt: new Date(),
    });
  }

  @OnWorkerEvent('completed')
  onCompleted(job: Job<EventJob>) {
    this.logger.debug(`Job ${job.id} completed for event ${job.data.eventType}`);
  }

  @OnWorkerEvent('failed')
  onFailed(job: Job<EventJob>, error: Error) {
    this.logger.error(
      `Job ${job.id} failed for event ${job.data.eventType}: ${error.message}`,
    );
  }
}
