import { Twilio } from 'twilio';
import {
  SMSNotification,
  NotificationStatus,
  NotificationPriority,
  NotificationRecipient,
  NotificationChannel,
} from '../types/notification.types';
import { TwilioConfig } from '../config/notification.config';

export class SMSService {
  private twilio: Twilio;
  private config: TwilioConfig;
  private defaultFromNumber?: string;

  constructor(config: TwilioConfig) {
    this.config = config;
    this.twilio = new Twilio(config.accountSid, config.authToken);
    this.defaultFromNumber = config.fromNumber;
  }

  /**
   * Send SMS message
   */
  async sendSMS(
    recipient: NotificationRecipient,
    body: string,
    fromNumber?: string
  ): Promise<SMSNotification> {
    const notification: SMSNotification = {
      id: `sms_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      userId: recipient.userId,
      channel: NotificationChannel.SMS,
      templateId: 'custom',
      priority: NotificationPriority.NORMAL,
      status: NotificationStatus.PENDING,
      to: recipient.phone!,
      body,
      from: fromNumber || this.defaultFromNumber,
      createdAt: new Date(),
    };

    if (!recipient.phone) {
      notification.status = NotificationStatus.FAILED;
      notification.failedAt = new Date();
      notification.errorMessage = 'Missing phone number';
      return notification;
    }

    try {
      const message = await this.twilio.messages.create({
        body,
        from: fromNumber || this.defaultFromNumber,
        to: recipient.phone,
      });

      notification.status = NotificationStatus.SENT;
      notification.sentAt = new Date();
      notification.id = message.sid;

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

  /**
   * Send SMS with delivery status tracking
   */
  async sendSMSWithTracking(
    recipient: NotificationRecipient,
    body: string,
    fromNumber?: string
  ): Promise<SMSNotification> {
    const notification = await this.sendSMS(recipient, body, fromNumber);

    if (notification.status === NotificationStatus.SENT && notification.id) {
      try {
        const message = await this.twilio.messages(notification.id).fetch();

        if (message.status === 'delivered') {
          notification.status = NotificationStatus.DELIVERED;
          notification.deliveredAt = new Date(message.dateUpdated || message.dateSent);
        }
      } catch (error) {
        console.warn(`Failed to fetch delivery status for SMS ${notification.id}:`, error);
      }
    }

    return notification;
  }

  /**
   * Check SMS delivery status
   */
  async getDeliveryStatus(smsId: string): Promise<NotificationStatus> {
    try {
      const message = await this.twilio.messages(smsId).fetch();

      switch (message.status) {
        case 'sent':
        case 'delivered':
          return NotificationStatus.DELIVERED;
        case 'failed':
        case 'undelivered':
          return NotificationStatus.FAILED;
        case 'queued':
        case 'sending':
          return NotificationStatus.PENDING;
        default:
          return NotificationStatus.PENDING;
      }
    } catch {
      return NotificationStatus.PENDING;
    }
  }

  /**
   * Send bulk SMS messages
   */
  async bulkSendSMS(
    recipients: Array<{
      recipient: NotificationRecipient;
      body: string;
      fromNumber?: string;
    }>
  ): Promise<SMSNotification[]> {
    const promises = recipients.map(async ({ recipient, body, fromNumber }) => {
      return this.sendSMS(recipient, body, fromNumber);
    });

    return Promise.all(promises);
  }

  /**
   * Send transactional SMS (e.g., verification codes)
   */
  async sendTransactionSMS(
    recipient: NotificationRecipient,
    template: 'verification' | 'password_reset' | 'welcome',
    variables?: Record<string, string>
  ): Promise<SMSNotification> {
    const templates: Record<string, (vars?: Record<string, string>) => string> = {
      verification: (vars) =>
        `Your verification code is: ${vars?.code || '123456'}. Valid for 10 minutes.`,
      password_reset: (vars) =>
        `Password reset requested for ${vars?.email || 'your account'}. Click the link to reset.`,
      welcome: (vars) =>
        `Welcome ${vars?.name || 'there'}! Your account has been created successfully.`,
    };

    const body = templates[template](variables);

    return this.sendSMS(recipient, body);
  }

  /**
   * Validate phone number format
   */
  isValidPhoneNumber(phone: string): boolean {
    // Basic E.164 format validation
    const e164Regex = /^\+[1-9]\d{1,14}$/;
    return e164Regex.test(phone);
  }

  /**
   * Get Twilio client for advanced operations
   */
  getClient(): Twilio {
    return this.twilio;
  }
}
