/**
 * Bulk Email Processor
 *
 * Processes bulk-email messages from the Communication SQS queue by sending the whole
 * batch in a single provider call (ZeptoMail /batch) via CommunicationService.
 * Per-recipient communication track rows are written by CommunicationService.sendBulkEmail
 * using each recipient's registrationId + the batch's templateId.
 */

import { Injectable } from '@nestjs/common';
import { QueueProcessor } from '../services/processor-registry.service';
import { QueueMessage, QueueProcessingResult } from '../interfaces/queue-message.interface';
import { QUEUE_CONSTANTS } from '../constants/queue.constants';
import { CommunicationService } from 'src/communication/communication.service';
import { SendBulkEmailDto } from 'src/communication/dto/email-communication.dto';
import { AwsS3Service } from 'src/common/services/awsS3.service';
import { classifyQueueError } from '../utils/queue-error.util';
import { resolveQueuedAttachments } from '../utils/queue-attachment.util';
import { AppLoggerService } from 'src/common/services/logger.service';

@Injectable()
export class BulkEmailProcessor implements QueueProcessor {
  constructor(
    private readonly communicationService: CommunicationService,
    private readonly awsS3Service: AwsS3Service,
    private readonly logger: AppLoggerService,
  ) {}

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

    if (
      message.queueType !== QUEUE_CONSTANTS.QUEUE_TYPES.COMMUNICATION ||
      message.subType !== QUEUE_CONSTANTS.COMMUNICATION_TYPES.BULK_EMAIL
    ) {
      return {
        success: false,
        messageId: message.messageId || 'unknown',
        queueType: message.queueType,
        processingTimeMs: Date.now() - startTime,
        error: {
          code: 'INVALID_MESSAGE_TYPE',
          message: `Expected bulk-email message, got: ${message.queueType}/${message.subType}`,
          retryable: false,
        },
      };
    }

    const bulkMessage = message;
    const recipientCount = bulkMessage.data.recipients?.length ?? 0;

    try {
      this.logger.debug(`Processing bulk-email message: ${recipientCount} recipients`);

      // Batch-level attachments arrive as S3 references; download them once for the whole batch
      // (they are identical for every recipient) via the same resolver EmailProcessor uses.
      const attachments = await resolveQueuedAttachments(
        bulkMessage.data.attachments,
        this.awsS3Service,
        this.logger,
        `bulk-email batch of ${recipientCount}`,
      );

      const dto: SendBulkEmailDto = {
        to: bulkMessage.data.recipients.map((recipient) => ({
          emailAddress: recipient.emailAddress,
          name: recipient.name,
          mergeInfo: recipient.templateData,
          registrationId: recipient.registrationId,
        })),
        from: {
          address: bulkMessage.data.from.address,
          name: bulkMessage.data.from.name,
        },
        subject: bulkMessage.data.subject,
        templateKey: bulkMessage.data.templateKey,
        attachments,
        trackinfo: {
          templateId: bulkMessage.metadata?.templateId,
          createdBy: bulkMessage.metadata?.createdBy,
          updatedBy: bulkMessage.metadata?.updatedBy,
        },
      };

      await this.communicationService.sendBulkEmail(dto);

      const processingTime = Date.now() - startTime;
      this.logger.log(
        `Successfully sent bulk email to ${recipientCount} recipients in ${processingTime}ms`,
      );

      return {
        success: true,
        messageId: bulkMessage.messageId || 'unknown',
        queueType: bulkMessage.queueType,
        processingTimeMs: processingTime,
      };
    } catch (error) {
      const classified = classifyQueueError(error);

      this.logger.error(`Failed to send bulk email to ${recipientCount} recipients`, '', {
        error: classified.message,
        stack: classified.stack,
        templateKey: bulkMessage.data.templateKey,
        attemptCount: bulkMessage.attemptCount,
      });

      return {
        success: false,
        messageId: bulkMessage.messageId || 'unknown',
        queueType: bulkMessage.queueType,
        processingTimeMs: Date.now() - startTime,
        error: {
          code: classified.code,
          message: classified.message,
          stack: classified.stack,
          retryable: classified.retryable,
        },
      };
    }
  }
}
