/**
 * WhatsApp Queue Service
 *
 * Queues WhatsApp template message jobs to the Communication SQS queue.
 */

import { Injectable } from '@nestjs/common';
import { SqsClientService } from './sqs-client.service';
import { QueueWhatsAppDto } from '../dto/queue-whatsapp.dto';
import { QueueBulkWhatsAppDto } from '../dto/queue-bulk-whatsapp.dto';
import {
  WhatsAppQueueMessage,
  BulkWhatsAppQueueMessage,
} from '../interfaces/queue-message.interface';
import { QUEUE_CONSTANTS } from '../constants/queue.constants';
import { getQueueFeatureFlags, getQueueUrls } from '../config/sqs.config';
import { AppLoggerService } from 'src/common/services/logger.service';
import { chunkArray } from 'src/common/utils/common.util';

@Injectable()
export class WhatsAppQueueService {
  private readonly queueUrl: string;
  private readonly queueEnabled: boolean;

  constructor(
    private readonly sqsClient: SqsClientService,
    private readonly logger: AppLoggerService,
  ) {
    const queueUrls = getQueueUrls();
    const featureFlags = getQueueFeatureFlags();

    this.queueUrl = queueUrls.communication || '';
    this.queueEnabled = featureFlags.communicationQueueEnabled && !!this.queueUrl;

    if (!this.queueEnabled) {
      this.logger.warn(
        'Communication queue is disabled or not configured. WhatsApp queue operations will be skipped.',
      );
    }
  }

  async queueWhatsAppMessage(
    messageData: QueueWhatsAppDto,
    correlationId?: string,
    userId?: string,
  ): Promise<string | null> {
    if (!this.queueEnabled) {
      this.logger.debug('WhatsApp queue is disabled - skipping queue operation');
      return null;
    }

    try {
      const message: WhatsAppQueueMessage = {
        queueType: QUEUE_CONSTANTS.QUEUE_TYPES.COMMUNICATION,
        subType: QUEUE_CONSTANTS.COMMUNICATION_TYPES.WHATSAPP,
        timestamp: new Date().toISOString(),
        correlationId: correlationId || `whatsapp-${Date.now()}`,
        userId: userId || messageData.userId,
        data: {
          phoneNumber: messageData.phoneNumber,
          templateName: messageData.templateName,
          parameters: messageData.parameters,
          broadcastName: messageData.broadcastName,
        },
        metadata: messageData.metadata,
      };

      const messageId = await this.sqsClient.sendMessage(this.queueUrl, message);
      this.logger.log(
        `WhatsApp message queued successfully: ${messageData.phoneNumber}, MessageId: ${messageId}`,
      );
      return messageId;
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.logger.error('Failed to queue WhatsApp message', '', {
        error: errorMessage,
        stack: error instanceof Error ? error.stack : undefined,
        phoneNumber: messageData.phoneNumber,
        templateName: messageData.templateName,
        correlationId,
        queueUrl: this.queueUrl,
      });
      return null;
    }
  }

  /**
   * Queue one or more bulk WhatsApp messages (WATI bulk template send).
   *
   * Mirrors EmailQueueService.queueBulkEmail: recipients are chunked at
   * QUEUE_CONSTANTS.BULK_WHATSAPP_BATCH_SIZE and each chunk is enqueued as its own SQS message,
   * which the processor then sends via CommunicationService.sendBulkTemplateMessage. Chunking
   * keeps every message well under the 256 KB SQS limit and keeps a single message's processing
   * time inside the communication queue's visibility timeout (the processor paces its WATI calls,
   * so one giant message could otherwise be redelivered while still sending).
   *
   * Tracking config (templateId/createdBy) is carried in metadata and applied per recipient
   * (with a registrationId) by the processor. A chunk that fails to enqueue is logged and skipped
   * — the remaining chunks still go out.
   *
   * @returns the SQS message ids for the enqueued chunks (empty if queue disabled / nothing queued)
   */
  async queueBulkWhatsApp(messageData: QueueBulkWhatsAppDto): Promise<string[]> {
    if (!this.queueEnabled) {
      this.logger.debug('WhatsApp queue is disabled - skipping bulk queue operation');
      return [];
    }

    if (!messageData.recipients || messageData.recipients.length === 0) {
      return [];
    }

    const chunks = chunkArray(messageData.recipients, QUEUE_CONSTANTS.BULK_WHATSAPP_BATCH_SIZE);
    const messageIds: string[] = [];

    for (let i = 0; i < chunks.length; i++) {
      const chunk = chunks[i];
      const chunkCorrelationId =
        messageData.correlationId ?? `bulk-whatsapp-${chunk[0]?.whatsappNumber ?? i}`;

      const message: BulkWhatsAppQueueMessage = {
        queueType: QUEUE_CONSTANTS.QUEUE_TYPES.COMMUNICATION,
        subType: QUEUE_CONSTANTS.COMMUNICATION_TYPES.BULK_WHATSAPP,
        timestamp: new Date().toISOString(),
        correlationId: chunks.length > 1 ? `${chunkCorrelationId}-${i}` : chunkCorrelationId,
        userId: messageData.userId,
        data: {
          templateName: messageData.templateName,
          broadcastName: messageData.broadcastName,
          recipients: chunk,
          // Batch-level, so every chunk needs its own copy.
          globalParameters: messageData.globalParameters,
        },
        metadata: {
          ...messageData.metadata,
          templateId: messageData.templateId,
          createdBy: messageData.createdBy,
          updatedBy: messageData.createdBy,
        },
      };

      try {
        const messageId = await this.sqsClient.sendMessage(this.queueUrl, message);
        if (messageId) {
          messageIds.push(messageId);
        }
      } catch (error) {
        this.logger.error('Failed to queue bulk-whatsapp chunk', '', {
          error: error instanceof Error ? error.message : String(error),
          stack: error instanceof Error ? error.stack : undefined,
          chunkIndex: i,
          recipientCount: chunk.length,
          templateName: messageData.templateName,
        });
      }
    }

    this.logger.log(
      `Queued ${messageData.recipients.length} recipient(s) as ${messageIds.length}/${chunks.length} bulk-whatsapp message(s)`,
    );
    return messageIds;
  }

  isQueueEnabled(): boolean {
    return this.queueEnabled;
  }

  getQueueUrl(): string {
    return this.queueUrl;
  }
}

