import { Resend } from 'resend';
import { ResendConfig } from '../config/notification.config';
import {
  EmailNotification,
  NotificationStatus,
  NotificationPriority,
  NotificationRecipient,
  NotificationChannel,
} from '../types/notification.types';

export class EmailService {
  private resend: Resend;
  private config: ResendConfig;

  constructor(config: ResendConfig) {
    this.config = config;
    this.resend = new Resend(config.apiKey);
  }

  /**
   * Send a transactional email
   */
  async sendEmail(
    recipient: NotificationRecipient,
    subject: string,
    htmlBody: string,
    textBody?: string,
    templateId?: string,
    attachments?: Array<{
      filename: string;
      content: Buffer | string;
      mimeType?: string;
    }>
  ): Promise<EmailNotification> {
    const notification: EmailNotification = {
      id: `email_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      userId: recipient.userId,
      channel: NotificationChannel.EMAIL,
      templateId: templateId || 'custom',
      priority: NotificationPriority.NORMAL,
      status: NotificationStatus.PENDING,
      to: recipient.email!,
      subject,
      htmlBody,
      textBody,
      attachments,
      createdAt: new Date(),
    };

    try {
      const { data, error } = await this.resend.emails.send({
        from: `${this.config.fromName} <${this.config.fromEmail}>`,
        to: [recipient.email!],
        subject,
        html: htmlBody,
        text: textBody,
        attachments: attachments?.map((att) => ({
          filename: att.filename,
          content: typeof att.content === 'string' ? Buffer.from(att.content) : att.content,
          mimeType: att.mimeType,
        })),
        metadata: {
          userId: recipient.userId,
          notificationId: notification.id,
        },
      });

      if (error) {
        notification.status = NotificationStatus.FAILED;
        notification.failedAt = new Date();
        notification.errorMessage = error.message;
      } else {
        notification.status = NotificationStatus.SENT;
        notification.sentAt = new Date();
      }

      return notification;
    } catch (error) {
      notification.status = NotificationStatus.FAILED;
      notification.failedAt = new Date();
      notification.errorMessage = error instanceof Error ? error.message : 'Unknown error';
      return notification;
    }
  }

  /**
   * Send email with retry logic
   */
  async sendEmailWithRetry(
    recipient: NotificationRecipient,
    subject: string,
    htmlBody: string,
    textBody?: string,
    maxRetries: number = 3
  ): Promise<EmailNotification> {
    let lastError: Error | undefined;

    for (let attempt = 0; attempt < maxRetries; attempt++) {
      try {
        const result = await this.sendEmail(recipient, subject, htmlBody, textBody);

        if (result.status === NotificationStatus.SENT) {
          return result;
        }

        lastError = new Error(result.errorMessage);
      } catch (error) {
        lastError = error as Error;
      }

      // Wait before retry (exponential backoff)
      await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
    }

    return {
      id: `email_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      userId: recipient.userId,
      channel: NotificationChannel.EMAIL,
      templateId: 'custom',
      priority: NotificationPriority.NORMAL,
      status: NotificationStatus.FAILED,
      to: recipient.email!,
      subject,
      htmlBody,
      textBody,
      createdAt: new Date(),
      failedAt: new Date(),
      errorMessage: lastError?.message,
    };
  }

  /**
   * Check email delivery status
   */
  async getDeliveryStatus(notificationId: string): Promise<NotificationStatus> {
    try {
      const emailId = notificationId.replace('email_', '');
      const { data } = await this.resend.emails.get(emailId);

      if (data.status === 'sent') {
        return NotificationStatus.SENT;
      } else if (data.status === 'delivered') {
        return NotificationStatus.DELIVERED;
      } else if (data.status === 'failed') {
        return NotificationStatus.FAILED;
      }

      return NotificationStatus.PENDING;
    } catch {
      return NotificationStatus.PENDING;
    }
  }

  /**
   * Batch send emails
   */
  async batchSendEmails(
    recipients: Array<{
      recipient: NotificationRecipient;
      subject: string;
      htmlBody: string;
      textBody?: string;
    }>
  ): Promise<EmailNotification[]> {
    const promises = recipients.map(async ({ recipient, subject, htmlBody, textBody }) => {
      return this.sendEmail(recipient, subject, htmlBody, textBody);
    });

    return Promise.all(promises);
  }
}
