/**
 * @ai-summary Notification handler for the email ingestion pipeline
 * @ai-context Encapsulates all email replies, in-app notifications, and notification logging
 *   for the email-to-record flow. Every email sent is logged to notification_logs.
 */

import { logger } from '../../../core/logging/logger';
import { NotificationsRepository } from '../../notifications/data/notifications.repository';
import { TemplateService } from '../../notifications/domain/template.service';
import { EmailService } from '../../notifications/domain/email.service';
import type { TemplateKey } from '../../notifications/domain/notifications.types';
import type { EmailRecordType, ExtractedReceiptData } from './email-ingestion.types';

export class EmailIngestionNotificationHandler {
  constructor(
    private notificationsRepository: NotificationsRepository,
    private templateService: TemplateService,
    private emailService: EmailService,
  ) {}

  // ========================
  // Success Notifications
  // ========================

  /**
   * Notify user that their emailed receipt was successfully processed.
   * Sends confirmation email + creates in-app notification + logs to notification_logs.
   */
  async notifyReceiptProcessed(params: {
    userId: string;
    userName: string;
    userEmail: string;
    vehicleName: string;
    recordType: EmailRecordType;
    recordId: string | null;
    vehicleId: string;
    extractedData: ExtractedReceiptData;
  }): Promise<void> {
    const { userId, userName, userEmail, vehicleName, recordType, recordId, vehicleId, extractedData } = params;
    const recordLabel = recordType === 'fuel_log' ? 'Fuel Log' : 'Maintenance Record';
    const merchantName = extractedData.vendor || extractedData.shopName || 'Unknown';

    // In-app notification
    const message = recordId
      ? `Your emailed ${recordLabel.toLowerCase()} receipt from ${merchantName} has been processed and recorded for ${vehicleName}.`
      : `Your emailed ${recordLabel.toLowerCase()} receipt from ${merchantName} was processed but the record could not be created automatically. Please add it manually.`;

    await this.notificationsRepository.insertUserNotification({
      userId,
      notificationType: 'email_ingestion',
      title: recordId ? 'Receipt Processed' : 'Receipt Partially Processed',
      message,
      referenceType: recordType,
      referenceId: recordId ?? undefined,
      vehicleId,
    });

    // Confirmation email
    await this.sendTemplateEmail({
      templateKey: 'receipt_processed',
      userId,
      userEmail,
      variables: {
        userName,
        vehicleName,
        recordType: recordLabel,
        merchantName,
        totalAmount: extractedData.total?.toFixed(2) || 'N/A',
        date: extractedData.date || 'N/A',
      },
      referenceType: 'email_ingestion',
      referenceId: recordId ?? undefined,
    });
  }

  // ========================
  // Pending Vehicle Notification
  // ========================

  /**
   * Notify multi-vehicle user that their receipt needs vehicle selection.
   * Sends pending-vehicle email + creates in-app notification + logs to notification_logs.
   */
  async notifyPendingVehicleSelection(params: {
    userId: string;
    userName: string;
    userEmail: string;
    recordType: EmailRecordType;
    pendingAssociationId: string;
    extractedData: ExtractedReceiptData;
  }): Promise<void> {
    const { userId, userName, userEmail, recordType, pendingAssociationId, extractedData } = params;
    const recordLabel = recordType === 'fuel_log' ? 'Fuel Log' : 'Maintenance Record';
    const merchantName = extractedData.vendor || extractedData.shopName || 'Unknown';

    // In-app notification
    await this.notificationsRepository.insertUserNotification({
      userId,
      notificationType: 'email_ingestion',
      title: 'Vehicle Selection Required',
      message: `Your emailed receipt from ${merchantName} has been processed. Please select which vehicle this ${recordLabel.toLowerCase()} belongs to.`,
      referenceType: 'pending_vehicle_association',
      referenceId: pendingAssociationId,
    });

    // Pending vehicle email
    await this.sendTemplateEmail({
      templateKey: 'receipt_pending_vehicle',
      userId,
      userEmail,
      variables: {
        userName,
        recordType: recordLabel,
        merchantName,
        totalAmount: extractedData.total?.toFixed(2) || 'N/A',
        date: extractedData.date || 'N/A',
      },
      referenceType: 'email_ingestion',
      referenceId: pendingAssociationId,
    });
  }

  // ========================
  // Error Notifications
  // ========================

  /**
   * Notify unregistered sender that their email was rejected.
   * Email reply only (no in-app notification since no user account).
   */
  async notifyUnregisteredSender(userEmail: string): Promise<void> {
    await this.sendTemplateEmail({
      templateKey: 'receipt_failed',
      userEmail,
      variables: {
        userName: 'MotoVaultPro User',
        errorReason: 'This email address is not registered with MotoVaultPro.',
        guidance: 'Please send receipts from the email address associated with your account. You can check your registered email in your MotoVaultPro profile settings.',
      },
      referenceType: 'email_ingestion',
    });
  }

  /**
   * Notify user that they must add a vehicle before emailing receipts.
   * Sends error email + creates in-app notification + logs to notification_logs.
   */
  async notifyNoVehicles(userId: string, userName: string, userEmail: string): Promise<void> {
    // In-app notification
    await this.notificationsRepository.insertUserNotification({
      userId,
      notificationType: 'email_ingestion',
      title: 'Receipt Processing Failed',
      message: 'Your emailed receipt could not be processed because you have no vehicles registered. Please add a vehicle first, then re-send your receipt.',
    });

    // Error email
    await this.sendTemplateEmail({
      templateKey: 'receipt_failed',
      userId,
      userEmail,
      variables: {
        userName,
        errorReason: 'You do not have any vehicles registered in MotoVaultPro.',
        guidance: 'Please add a vehicle first in the MotoVaultPro app, then re-send your receipt.',
      },
      referenceType: 'email_ingestion',
    });
  }

  /**
   * Notify user that no valid attachments were found in their email.
   * Sends error email + creates in-app notification + logs to notification_logs.
   */
  async notifyNoValidAttachments(userId: string, userName: string, userEmail: string): Promise<void> {
    // In-app notification
    await this.notificationsRepository.insertUserNotification({
      userId,
      notificationType: 'email_ingestion',
      title: 'Receipt Processing Failed',
      message: 'No valid attachments were found in your email. Please attach receipt images (PNG, JPG, JPEG, HEIC) or PDFs under 10MB.',
    });

    // Error email
    await this.sendTemplateEmail({
      templateKey: 'receipt_failed',
      userId,
      userEmail,
      variables: {
        userName,
        errorReason: 'No valid attachments were found in your email.',
        guidance: 'Please attach receipt images (PNG, JPG, JPEG, HEIC) or PDFs under 10MB. Make sure your receipt is clearly visible in the image.',
      },
      referenceType: 'email_ingestion',
    });
  }

  /**
   * Notify user that OCR extraction failed after all attempts.
   * Sends error email + creates in-app notification + logs to notification_logs.
   */
  async notifyOcrFailure(userId: string, userName: string, userEmail: string, reason: string): Promise<void> {
    // In-app notification
    await this.notificationsRepository.insertUserNotification({
      userId,
      notificationType: 'email_ingestion',
      title: 'Receipt Processing Failed',
      message: `We could not extract data from your receipt: ${reason}`,
    });

    // Error email
    await this.sendTemplateEmail({
      templateKey: 'receipt_failed',
      userId,
      userEmail,
      variables: {
        userName,
        errorReason: reason,
        guidance: 'Please try again with a clearer image or PDF. Tips: use a well-lit, high-contrast photo; ensure text is legible and not cut off; PDF receipts work best.',
      },
      referenceType: 'email_ingestion',
    });
  }

  /**
   * Notify user of a general processing failure (after max retries exceeded).
   * Sends error email + creates in-app notification (if userId available) + logs.
   */
  async notifyProcessingFailure(params: {
    userId?: string;
    userName?: string;
    userEmail: string;
    errorReason: string;
  }): Promise<void> {
    const { userId, userName, userEmail, errorReason } = params;

    // In-app notification (only if we have a userId)
    if (userId) {
      await this.notificationsRepository.insertUserNotification({
        userId,
        notificationType: 'email_ingestion',
        title: 'Receipt Processing Failed',
        message: `Your emailed receipt could not be processed: ${errorReason}`,
      });
    }

    // Error email
    await this.sendTemplateEmail({
      templateKey: 'receipt_failed',
      userId,
      userEmail,
      variables: {
        userName: userName || 'MotoVaultPro User',
        errorReason,
        guidance: 'Please try again or upload the receipt directly through the MotoVaultPro app.',
      },
      referenceType: 'email_ingestion',
    });
  }

  // ========================
  // Internal Helpers
  // ========================

  /**
   * Send a templated email and log to notification_logs.
   * Swallows errors to prevent notification failures from breaking the pipeline.
   */
  private async sendTemplateEmail(params: {
    templateKey: TemplateKey;
    userId?: string;
    userEmail: string;
    variables: Record<string, string | number | boolean | null | undefined>;
    referenceType?: string;
    referenceId?: string;
  }): Promise<void> {
    const { templateKey, userId, userEmail, variables, referenceType, referenceId } = params;

    try {
      const template = await this.notificationsRepository.getEmailTemplateByKey(templateKey);
      if (!template || !template.isActive) {
        logger.warn('Email template not found or inactive', { templateKey });
        return;
      }

      const renderedSubject = this.templateService.render(template.subject, variables);
      const renderedHtml = this.templateService.renderEmailHtml(template.body, variables);

      await this.emailService.send(userEmail, renderedSubject, renderedHtml);

      // Log successful send
      if (userId) {
        await this.notificationsRepository.insertNotificationLog({
          user_id: userId,
          notification_type: 'email',
          template_key: templateKey,
          recipient_email: userEmail,
          subject: renderedSubject,
          reference_type: referenceType,
          reference_id: referenceId,
          status: 'sent',
        });
      }

      logger.info('Email ingestion notification sent', { templateKey, userEmail });
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      logger.error('Failed to send email ingestion notification', {
        templateKey,
        userEmail,
        error: errorMessage,
      });

      // Log failed send
      if (userId) {
        await this.notificationsRepository.insertNotificationLog({
          user_id: userId,
          notification_type: 'email',
          template_key: templateKey,
          recipient_email: userEmail,
          reference_type: referenceType,
          reference_id: referenceId,
          status: 'failed',
          error_message: errorMessage,
        }).catch(logErr => {
          logger.error('Failed to log notification failure', {
            error: logErr instanceof Error ? logErr.message : String(logErr),
          });
        });
      }
    }
  }
}
