/**
 * Email Processor
 * 
 * Processes email messages from the SQS queue by calling the CommunicationService.
 * This processor:
 * 1. Receives email messages from the queue
 * 2. Transforms them to CommunicationService format
 * 3. Calls the existing email sending logic
 * 4. Returns success/failure result
 */

import { Injectable } from '@nestjs/common';
import { QueueProcessor } from '../services/processor-registry.service';
import {
  QueueMessage,
  EmailQueueMessage,
  QueueProcessingResult,
} from '../interfaces/queue-message.interface';
import { QUEUE_CONSTANTS } from '../constants/queue.constants';
import { CommunicationService } from 'src/communication/communication.service';
import { SendSingleEmailDto } 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 { maskEmailAddress } from '../utils/pii-mask.util';
import { AppLoggerService } from 'src/common/services/logger.service';

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

  /**
   * Process an email message from the queue
   */
  async process(message: QueueMessage): Promise<QueueProcessingResult> {
    const startTime = Date.now();

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

    const emailMessage = message as EmailQueueMessage;

    try {
      this.logger.debug(
        `Processing email message: ${maskEmailAddress(emailMessage.data.to.emailAddress)} ` +
        `(Attempt: ${emailMessage.attemptCount})`
      );

      // Resolve attachments (inline bytes passed through, s3Key references downloaded) via the
      // shared resolver, so this and BulkEmailProcessor can't drift on retry/skip behaviour.
      const validAttachments = await resolveQueuedAttachments(
        emailMessage.data.attachments,
        this.awsS3Service,
        this.logger,
        `email ${maskEmailAddress(emailMessage.data.to.emailAddress)}`,
      );

      // Transform queue message to CommunicationService DTO
      const emailDto: SendSingleEmailDto = {
        to: {
          emailAddress: emailMessage.data.to.emailAddress,
          name: emailMessage.data.to.name,
        },
        from: {
          address: emailMessage.data.from.address,
          name: emailMessage.data.from.name,
        },
        subject: emailMessage.data.subject,
        htmlbody: emailMessage.data.htmlBody,
        textbody: emailMessage.data.textBody,
        templateKey: emailMessage.data.templateKey,
        mergeInfo: emailMessage.data.templateData,
        cc: emailMessage.data.cc?.map(cc => ({
          emailAddress: cc.emailAddress,
          name: cc.name,
        })),
        bcc: emailMessage.data.bcc?.map(bcc => ({
          emailAddress: bcc.emailAddress,
          name: bcc.name,
        })),
        attachments: validAttachments as any, // Already filtered for null values
      } as any; // Use 'as any' to bypass trackinfo type checking

      // Add trackinfo if available
      if (emailMessage.metadata?.registrationId) {
        emailDto.trackinfo = {
          registrationId: emailMessage.metadata.registrationId,
          createdBy: emailMessage.metadata.createdBy,
          updatedBy: emailMessage.metadata.updatedBy,
          templateId: emailMessage.metadata.templateId,
        };
      }

      // Call the existing CommunicationService
      await this.communicationService.sendSingleEmail(emailDto);

      const processingTime = Date.now() - startTime;

      this.logger.log(
        `Successfully sent email to: ${maskEmailAddress(emailMessage.data.to.emailAddress)} ` +
        `in ${processingTime}ms`
      );

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

      this.logger.error(
        `Failed to send email to: ${maskEmailAddress(emailMessage.data.to.emailAddress)}`,
        '',
        {
          error: classified.message,
          stack: classified.stack,
          to: emailMessage.data.to.emailAddress,
          templateKey: emailMessage.data.templateKey,
          attemptCount: emailMessage.attemptCount,
        },
      );
      this.logger.error(`Email sending queue failed: ${JSON.stringify(error)}`);

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