/**
 * Notification service for credential issuance
 * Supports email, SMS, and push notifications
 */

import { getEnv } from '@the-order/shared';

export interface NotificationConfig {
  email?: {
    provider: 'smtp' | 'sendgrid' | 'ses' | 'sendinblue';
    apiKey?: string;
    fromEmail?: string;
    fromName?: string;
  };
  sms?: {
    provider: 'twilio' | 'aws-sns' | 'nexmo';
    apiKey?: string;
    fromNumber?: string;
  };
  push?: {
    provider: 'fcm' | 'apns' | 'web-push';
    apiKey?: string;
  };
}

export interface NotificationRequest {
  to: string | string[];
  subject?: string;
  message: string;
  type: 'email' | 'sms' | 'push';
  template?: string;
  templateData?: Record<string, unknown>;
  priority?: 'low' | 'normal' | 'high';
}

export interface NotificationResult {
  success: boolean;
  messageId?: string;
  error?: string;
}

/**
 * Notification Service
 */
export class NotificationService {
  private config: NotificationConfig;

  constructor(config?: NotificationConfig) {
    const env = getEnv();
    this.config = config || {
      email: {
        provider: (env.EMAIL_PROVIDER as 'smtp' | 'sendgrid' | 'ses' | 'sendinblue') || 'smtp',
        apiKey: env.EMAIL_API_KEY,
        fromEmail: env.EMAIL_FROM || 'noreply@theorder.org',
        fromName: env.EMAIL_FROM_NAME || 'The Order',
      },
      sms: {
        provider: (env.SMS_PROVIDER as 'twilio' | 'aws-sns' | 'nexmo') || 'twilio',
        apiKey: env.SMS_API_KEY,
        fromNumber: env.SMS_FROM_NUMBER,
      },
      push: {
        provider: (env.PUSH_PROVIDER as 'fcm' | 'apns' | 'web-push') || 'fcm',
        apiKey: env.PUSH_API_KEY,
      },
    };
  }

  /**
   * Send notification
   */
  async send(notification: NotificationRequest): Promise<NotificationResult> {
    try {
      switch (notification.type) {
        case 'email':
          return await this.sendEmail(notification);
        case 'sms':
          return await this.sendSMS(notification);
        case 'push':
          return await this.sendPush(notification);
        default:
          return { success: false, error: `Unsupported notification type: ${notification.type}` };
      }
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  /**
   * Send email notification
   */
  private async sendEmail(notification: NotificationRequest): Promise<NotificationResult> {
    if (!this.config.email) {
      return { success: false, error: 'Email provider not configured' };
    }

    const recipients = Array.isArray(notification.to) ? notification.to : [notification.to];
    const message = notification.template
      ? this.renderTemplate(notification.template, notification.templateData || {})
      : notification.message;

    // In production, integrate with actual email provider
    // For now, log the email
    console.log('Email notification:', {
      to: recipients,
      subject: notification.subject || 'Notification from The Order',
      message,
      provider: this.config.email.provider,
    });

    return {
      success: true,
      messageId: `email-${Date.now()}`,
    };
  }

  /**
   * Send SMS notification
   */
  private async sendSMS(notification: NotificationRequest): Promise<NotificationResult> {
    if (!this.config.sms) {
      return { success: false, error: 'SMS provider not configured' };
    }

    const recipients = Array.isArray(notification.to) ? notification.to : [notification.to];
    const message = notification.template
      ? this.renderTemplate(notification.template, notification.templateData || {})
      : notification.message;

    // In production, integrate with actual SMS provider
    console.log('SMS notification:', {
      to: recipients,
      message,
      provider: this.config.sms.provider,
    });

    return {
      success: true,
      messageId: `sms-${Date.now()}`,
    };
  }

  /**
   * Send push notification
   */
  private async sendPush(notification: NotificationRequest): Promise<NotificationResult> {
    if (!this.config.push) {
      return { success: false, error: 'Push provider not configured' };
    }

    const recipients = Array.isArray(notification.to) ? notification.to : [notification.to];
    const message = notification.template
      ? this.renderTemplate(notification.template, notification.templateData || {})
      : notification.message;

    // In production, integrate with actual push provider
    console.log('Push notification:', {
      to: recipients,
      message,
      provider: this.config.push.provider,
    });

    return {
      success: true,
      messageId: `push-${Date.now()}`,
    };
  }

  /**
   * Render template with variables
   */
  private renderTemplate(template: string, data: Record<string, unknown>): string {
    let rendered = template;
    for (const [key, value] of Object.entries(data)) {
      const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
      rendered = rendered.replace(regex, String(value));
    }
    return rendered;
  }
}

/**
 * Notification templates for credential issuance
 */
export const CredentialNotificationTemplates = {
  ISSUED: {
    email: {
      subject: 'Your Verifiable Credential Has Been Issued',
      template: `Dear {{recipientName}},

Your verifiable credential has been successfully issued.

Credential Type: {{credentialType}}
Issued By: {{issuerName}}
Issued At: {{issuedAt}}
Credential ID: {{credentialId}}

You can view and manage your credentials at: {{credentialsUrl}}

Best regards,
The Order`,
    },
    sms: {
      template: `Your {{credentialType}} credential has been issued. ID: {{credentialId}}. View at {{credentialsUrl}}`,
    },
    push: {
      title: 'Credential Issued',
      body: 'Your {{credentialType}} credential has been issued',
    },
  },
  RENEWED: {
    email: {
      subject: 'Your Verifiable Credential Has Been Renewed',
      template: `Dear {{recipientName}},

Your verifiable credential has been renewed.

Credential Type: {{credentialType}}
New Credential ID: {{newCredentialId}}
Previous Credential ID: {{oldCredentialId}}
Renewed At: {{renewedAt}}

You can view and manage your credentials at: {{credentialsUrl}}

Best regards,
The Order`,
    },
    sms: {
      template: `Your {{credentialType}} credential has been renewed. New ID: {{newCredentialId}}`,
    },
    push: {
      title: 'Credential Renewed',
      body: 'Your {{credentialType}} credential has been renewed',
    },
  },
  EXPIRING: {
    email: {
      subject: 'Your Verifiable Credential Is Expiring Soon',
      template: `Dear {{recipientName}},

Your verifiable credential will expire soon.

Credential Type: {{credentialType}}
Credential ID: {{credentialId}}
Expiration Date: {{expirationDate}}
Days Until Expiration: {{daysUntilExpiration}}

Please renew your credential before it expires.

Renew at: {{renewalUrl}}

Best regards,
The Order`,
    },
    sms: {
      template: `Your {{credentialType}} credential expires in {{daysUntilExpiration}} days. Renew at {{renewalUrl}}`,
    },
    push: {
      title: 'Credential Expiring',
      body: 'Your {{credentialType}} credential expires in {{daysUntilExpiration}} days',
    },
  },
  REVOKED: {
    email: {
      subject: 'Your Verifiable Credential Has Been Revoked',
      template: `Dear {{recipientName}},

Your verifiable credential has been revoked.

Credential Type: {{credentialType}}
Credential ID: {{credentialId}}
Revoked At: {{revokedAt}}
Reason: {{revocationReason}}

If you believe this is an error, please contact support.

Best regards,
The Order`,
    },
    sms: {
      template: `Your {{credentialType}} credential (ID: {{credentialId}}) has been revoked. Reason: {{revocationReason}}`,
    },
    push: {
      title: 'Credential Revoked',
      body: 'Your {{credentialType}} credential has been revoked',
    },
  },
};

/**
 * Get default notification service instance
 */
let defaultNotificationService: NotificationService | null = null;

export function getNotificationService(): NotificationService {
  if (!defaultNotificationService) {
    defaultNotificationService = new NotificationService();
  }
  return defaultNotificationService;
}

