import { EmailService } from './email.service';
import { PushService } from './push.service';
import { SMSService } from './sms.service';
import {
  Notification,
  NotificationChannel,
  NotificationPreferences,
  NotificationRecipient,
  NotificationStatus,
  NotificationPriority,
} from '../types/notification.types';
import { NotificationConfig } from '../config/notification.config';

/**
 * Main notification service that orchestrates all notification channels
 */
export class NotificationService {
  private emailService?: EmailService;
  private pushService?: PushService;
  private smsService?: SMSService;
  private config: NotificationConfig;

  constructor(config: NotificationConfig) {
    this.config = config;

    // Initialize services based on configuration
    if (config.resend) {
      this.emailService = new EmailService(config.resend);
    }

    if (config.fcm || config.apns) {
      this.pushService = new PushService(config.fcm, config.apns);
    }

    if (config.twilio) {
      this.smsService = new SMSService(config.twilio);
    }
  }

  /**
   * Send notification to all enabled channels for a user
   */
  async sendMultiChannelNotification(
    recipient: NotificationRecipient,
    channel: NotificationChannel | NotificationChannel[],
    subject: string,
    body: string,
    priority: NotificationPriority = NotificationPriority.NORMAL,
    metadata?: Record<string, unknown>
  ): Promise<Notification[]> {
    const channels = Array.isArray(channel) ? channel : [channel];
    const notifications: Notification[] = [];

    for (const ch of channels) {
      const prefs = await this.getNotificationPreferences(recipient.userId);

      if (!this.isChannelEnabled(prefs, ch)) {
        continue;
      }

      let notification: Notification;

      switch (ch) {
        case NotificationChannel.EMAIL:
          if (this.emailService && recipient.email) {
            notification = await this.emailService.sendEmail(
              recipient,
              subject,
              body,
              body // Plain text fallback
            );
            notifications.push(notification);
          }
          break;

        case NotificationChannel.PUSH:
          if (this.pushService) {
            notification = await this.pushService.sendPush(
              recipient,
              subject,
              body,
              metadata as Record<string, unknown>,
              undefined,
              'default'
            );
            notifications.push(notification);
          }
          break;

        case NotificationChannel.SMS:
          if (this.smsService && recipient.phone) {
            notification = await this.smsService.sendSMS(recipient, body);
            notifications.push(notification);
          }
          break;
      }
    }

    return notifications;
  }

  /**
   * Send email notification
   */
  async sendEmail(
    recipient: NotificationRecipient,
    subject: string,
    htmlBody: string,
    textBody?: string
  ): Promise<Notification | null> {
    if (!this.emailService) {
      return null;
    }

    return this.emailService.sendEmail(recipient, subject, htmlBody, textBody);
  }

  /**
   * Send push notification
   */
  async sendPush(
    recipient: NotificationRecipient,
    title: string,
    body: string,
    data?: Record<string, unknown>
  ): Promise<Notification | null> {
    if (!this.pushService) {
      return null;
    }

    return this.pushService.sendPush(recipient, title, body, data);
  }

  /**
   * Send SMS notification
   */
  async sendSMS(
    recipient: NotificationRecipient,
    body: string,
    fromNumber?: string
  ): Promise<Notification | null> {
    if (!this.smsService) {
      return null;
    }

    return this.smsService.sendSMS(recipient, body, fromNumber);
  }

  /**
   * Get notification preferences for a user
   */
  async getNotificationPreferences(
    userId: string
  ): Promise<NotificationPreferences> {
    // TODO: Fetch from database
    // For now, return default preferences
    return {
      userId,
      email: {
        enabled: true,
        categories: ['marketing', 'transactional', 'alerts'],
      },
      push: {
        enabled: true,
        categories: ['marketing', 'transactional', 'alerts'],
      },
      sms: {
        enabled: true,
        categories: ['alerts'],
      },
    };
  }

  /**
   * Check if a channel is enabled for a user
   */
  private isChannelEnabled(
    prefs: NotificationPreferences,
    channel: NotificationChannel
  ): boolean {
    switch (channel) {
      case NotificationChannel.EMAIL:
        return prefs.email.enabled;
      case NotificationChannel.PUSH:
        return prefs.push.enabled;
      case NotificationChannel.SMS:
        return prefs.sms.enabled;
    }
  }

  /**
   * Deduplicate notifications (prevent duplicate sends)
   */
  async deduplicateNotification(
    userId: string,
    templateId: string,
    windowMs: number = 5 * 60 * 1000 // 5 minutes default
  ): Promise<boolean> {
    // TODO: Check recent notifications in database
    // For now, return true (not a duplicate)
    return true;
  }

  /**
   * Check rate limit for a channel
   */
  async checkRateLimit(
    userId: string,
    channel: NotificationChannel
  ): Promise<{ allowed: boolean; remaining: number; resetAt: Date }> {
    const rateLimit = this.config.rateLimits[channel];

    // TODO: Implement actual rate limiting with Redis or database
    // For now, return default values
    return {
      allowed: true,
      remaining: rateLimit.maxPerWindow,
      resetAt: new Date(Date.now() + rateLimit.windowMs),
    };
  }

  /**
   * Get email service instance
   */
  getEmailService(): EmailService | undefined {
    return this.emailService;
  }

  /**
   * Get push service instance
   */
  getPushService(): PushService | undefined {
    return this.pushService;
  }

  /**
   * Get SMS service instance
   */
  getSMSService(): SMSService | undefined {
    return this.smsService;
  }

  /**
   * Check if all services are initialized
   */
  isFullyConfigured(): boolean {
    return !!(this.emailService && this.pushService && this.smsService);
  }

  /**
   * Get configuration summary
   */
  getConfigSummary(): {
    email: boolean;
    push: boolean;
    sms: boolean;
  } {
    return {
      email: !!this.emailService,
      push: !!this.pushService,
      sms: !!this.smsService,
    };
  }
}

// Export singleton instance creator
export function createNotificationService(
  config: NotificationConfig
): NotificationService {
  return new NotificationService(config);
}
