// Handles `join-link-generation` messages; delegates the run to
// JoinLinkGenerationService (shared with the 4-hourly fallback cron).
import { Injectable } from '@nestjs/common';
import { QueueProcessor } from '../services/processor-registry.service';
import {
  QueueMessage,
  QueueProcessingResult,
  JoinLinkGenerationQueueMessage,
} from '../interfaces/queue-message.interface';
import { QUEUE_CONSTANTS } from '../constants/queue.constants';
import { classifyQueueError } from '../utils/queue-error.util';
import { AppLoggerService } from 'src/common/services/logger.service';
import { JoinLinkGenerationService } from 'src/join-link-generation/join-link-generation.service';

@Injectable()
export class JoinLinkGenerationProcessor implements QueueProcessor {
  constructor(
    private readonly generationService: JoinLinkGenerationService,
    private readonly logger: AppLoggerService,
  ) {}

  async process(message: QueueMessage): Promise<QueueProcessingResult> {
    const startTime = Date.now();

    // Type guard (AGENTS.md §2: Type Safety)
    if (
      message.queueType !== QUEUE_CONSTANTS.QUEUE_TYPES.EVENT ||
      message.subType !== QUEUE_CONSTANTS.EVENT_TYPES.JOIN_LINK_GENERATION
    ) {
      return this.failure(message, startTime, {
        code: 'INVALID_MESSAGE_TYPE',
        message: `Expected join-link-generation message, got: ${message.queueType}/${message.subType}`,
        retryable: false,
      });
    }

    const { data } = message as JoinLinkGenerationQueueMessage;
    const { programSessionId, role, batchSize, actorUserId } = data;

    if (!programSessionId) {
      return this.failure(message, startTime, {
        code: QUEUE_CONSTANTS.ERROR_TYPES.VALIDATION_ERROR,
        message: 'join-link-generation message is missing programSessionId',
        retryable: false,
      });
    }

    try {
      await this.generationService.generateForSession(programSessionId, {
        role,
        batchSize,
        actorUserId,
      });
      this.logger.log(
        `join-link-generation processed: programSessionId=${programSessionId}, ` +
          `attempt=${message.attemptCount || 1}`,
      );
      return {
        success: true,
        messageId: message.messageId || 'unknown',
        queueType: message.queueType,
        processingTimeMs: Date.now() - startTime,
      };
    } catch (error) {
      const classified = classifyQueueError(error);
      this.logger.error(
        `Failed to trigger join-link generation: programSessionId=${programSessionId}`,
        classified.stack ?? '',
        { programSessionId, error: classified.message, attemptCount: message.attemptCount },
      );
      return this.failure(message, startTime, {
        code: classified.code,
        message: classified.message,
        retryable: classified.retryable,
        stack: classified.stack,
      });
    }
  }

  private failure(
    message: QueueMessage,
    startTime: number,
    error: { code: string; message: string; retryable: boolean; stack?: string },
  ): QueueProcessingResult {
    return {
      success: false,
      messageId: message.messageId || 'unknown',
      queueType: message.queueType,
      processingTimeMs: Date.now() - startTime,
      error,
    };
  }
}
