/**
 * Invoice Processor
 *
 * Processes invoice generation jobs from the Heavy Processing SQS queue.
 *
 * - REGULAR context: generate post-payment invoice (online/offline) + send communications
 * - PROFORMA context: generate pre-payment proforma invoice + send communications
 *
 * Note: For regular invoices, the invoice type (online/offline) is automatically determined
 * from the payment mode in the database. Do NOT pass invoice type explicitly.
 */

import { Injectable } from '@nestjs/common';
import { QueueProcessor } from '../services/processor-registry.service';
import { InvoiceQueueMessage, QueueMessage, QueueProcessingResult } from '../interfaces/queue-message.interface';
import { QUEUE_CONSTANTS } from '../constants/queue.constants';
import { InvoiceService } from 'src/invoice/invoice.service';
import { RegistrationApprovalService } from 'src/registration-approval/registration-approval.service';
import { BrowserManagerService } from 'src/common/services/browser-manager.service';
import { classifyQueueError } from '../utils/queue-error.util';
import { AppLoggerService } from 'src/common/services/logger.service';
import { InvoiceContextEnum } from 'src/common/enum/invoice-context.enum';

@Injectable()
export class InvoiceProcessor implements QueueProcessor {
  constructor(
    private readonly invoiceService: InvoiceService,
    private readonly registrationApprovalService: RegistrationApprovalService,
    private readonly browserManagerService: BrowserManagerService,
    private readonly logger: AppLoggerService,
  ) {}

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

    // Type guard (AGENTS.md §1: Type Safety)
    if (
      message.queueType !== QUEUE_CONSTANTS.QUEUE_TYPES.HEAVY_PROCESSING ||
      message.subType !== QUEUE_CONSTANTS.HEAVY_PROCESSING_TYPES.INVOICE
    ) {
      return {
        success: false,
        messageId: message.messageId || 'unknown',
        queueType: message.queueType,
        processingTimeMs: Date.now() - startTime,
        error: {
          code: 'INVALID_MESSAGE_TYPE',
          message: `Expected invoice message, got: ${message.queueType}/${message.subType}`,
          retryable: false,
        },
      };
    }

    const invoiceMessage = message as InvoiceQueueMessage;

    this.logger.log(
      `Processing invoice: registrationId=${invoiceMessage.data.registrationId}, ` +
      `context=${invoiceMessage.data.invoiceContext}, ` +
      `attempt=${invoiceMessage.attemptCount || 1}`,
    );

    try {
      if (invoiceMessage.data.invoiceContext === InvoiceContextEnum.PROFORMA) {
        // ✅ Proforma invoice for blessed seekers
        await this.registrationApprovalService.generateAndSendProformaInvoiceCommunication(
          invoiceMessage.data.registrationId,
          invoiceMessage.data.sendEmail ?? true,
          invoiceMessage.data.sendWhatsApp ?? false,
        );
      } else {
        // ✅ Regular post-payment invoice - calls _generateAndSendInvoiceSync
        await this.invoiceService._generateAndSendInvoiceSync(
          invoiceMessage.data.registrationId,
          invoiceMessage.data.userId,
          invoiceMessage.data.sendEmail ?? true,
        );
      }

      // Periodic browser cleanup (10% chance)
      if (Math.random() < 0.1) {
        this.logger.debug('Triggering browser resource cleanup');
        await this.browserManagerService.cleanupBrowserResources();
      }

      const processingTime = Date.now() - startTime;

      this.logger.log(
        `Successfully processed invoice in ${processingTime}ms: ` +
        `registrationId=${invoiceMessage.data.registrationId}`,
      );

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

      const errorMessage = classified.message;
      const errorStack = classified.stack;

      this.logger.error(
        `Failed to process invoice: registrationId=${invoiceMessage.data.registrationId}`,
        '',
        {
          error: errorMessage,
          stack: errorStack,
          registrationId: invoiceMessage.data.registrationId,
          invoiceContext: invoiceMessage.data.invoiceContext,
          attemptCount: invoiceMessage.attemptCount,
        },
      );

      // Preserve existing non-retryable conditions (data issues)
      const nonRetryable = this.isNonRetryableErrorMessage(errorMessage);
      const retryable = nonRetryable ? false : classified.retryable;
      const code = nonRetryable ? QUEUE_CONSTANTS.ERROR_TYPES.VALIDATION_ERROR : classified.code;

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

  /**
   * Determine if error is retryable
   * Following coding standard: Error Handling (AGENTS.md §2)
   */
  private isNonRetryableErrorMessage(errorMessage: string): boolean {
    const message = (errorMessage || '').toLowerCase();
    return (
      message.includes('invoice not found') ||
      message.includes('payment not completed') ||
      message.includes('registration not found') ||
      message.includes('invalid invoice data')
    );
  }
}

