import { Resend } from 'resend';
import { loadNotificationConfig } from '../config/notification.config';
import type { EmailNotification, NotificationResult } from '../types/notification.types';
import type { TemplateResolutionOptions } from '../types/template.types';
import { TemplateService } from './template.service';

const config = loadNotificationConfig();
const resend = new Resend(config.resend.apiKey);

interface RateLimitEntry {
  count: number;
  lastSentAt: number;
}

const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

export class EmailService {
  private static instance: EmailService;
  private sentCount = new Map<string, RateLimitEntry>();
  private cleanupInterval: NodeJS.Timeout;

  private constructor() {
    this.cleanupInterval = setInterval(() => {
      const now = Date.now();
      for (const [key, entry] of this.sentCount.entries()) {
        if (now - entry.lastSentAt > 60000) {
          this.sentCount.delete(key);
        }
      }
    }, 60000);
  }

  private validateEmail(email: string): boolean {
    return EMAIL_PATTERN.test(email);
  }

  static getInstance(): EmailService {
    if (!EmailService.instance) {
      EmailService.instance = new EmailService();
    }
    return EmailService.instance;
  }

  async send(notification: EmailNotification): Promise<NotificationResult> {
    const rateLimitKey = `email:${notification.to}`;
    const entry = this.sentCount.get(rateLimitKey) || { count: 0, lastSentAt: Date.now() };

    if (entry.count >= config.rateLimits.emailPerMinute) {
      throw new Error(`Email rate limit exceeded for ${notification.to}`);
    }

    if (!this.validateEmail(notification.to)) {
      throw new Error(`Invalid email format: ${notification.to}`);
    }

    try {
      const { data, error } = await resend.emails.send({
        from: notification.from || 'ShieldAI <noreply@shieldai.com>',
        to: [notification.to],
        subject: notification.subject,
        html: notification.htmlBody,
        text: notification.textBody,
        metadata: notification.metadata,
        attachments: notification.attachments?.map(att => ({
          filename: att.filename,
          data: att.content,
          contentType: att.mimeType,
        })),
      });

      if (error) {
        return {
          notificationId: `email-${Date.now()}`,
          channel: 'email',
          status: 'failed',
          externalId: data?.id,
          error: error.message,
        };
      }

      this.sentCount.set(rateLimitKey, { 
      count: entry.count + 1, 
      lastSentAt: Date.now() 
    });

      return {
        notificationId: `email-${data?.id || Date.now()}`,
        channel: 'email',
        status: 'sent',
        externalId: data?.id,
        deliveredAt: new Date(),
      };
    } catch (error) {
      return {
        notificationId: `email-${Date.now()}`,
        channel: 'email',
        status: 'failed',
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  async sendWithTemplate(
    to: string,
    options: TemplateResolutionOptions & { from?: string }
  ): Promise<NotificationResult> {
    const templateService = TemplateService.getInstance();
    const resolved = templateService.resolveTemplate({
      templateId: options.templateId,
      locale: options.locale,
      variables: options.variables,
      fallbackLocale: options.fallbackLocale,
    });

    if (!resolved) {
      return {
        notificationId: `email-${Date.now()}`,
        channel: 'email',
        status: 'failed',
        error: `Template not found: ${options.templateId}`,
      };
    }

    if (resolved.channel !== 'email') {
      return {
        notificationId: `email-${Date.now()}`,
        channel: 'email',
        status: 'failed',
        error: `Template ${options.templateId} is for channel '${resolved.channel}', not 'email'`,
      };
    }

    const notification: EmailNotification = {
      channel: 'email',
      to,
      from: options.from,
      subject: resolved.subject || '',
      htmlBody: resolved.htmlBody || resolved.body,
      textBody: resolved.body,
    };

    return this.send(notification);
  }

  async sendBatch(notifications: EmailNotification[]): Promise<NotificationResult[]> {
    const results = await Promise.all(
      notifications.map(n => this.send(n))
    );
    return results;
  }

  getRateLimitStatus(): { remaining: number; limit: number } {
    return {
      remaining: config.rateLimits.emailPerMinute - this.sentCount.size,
      limit: config.rateLimits.emailPerMinute,
    };
  }
}
