import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Twilio } from 'twilio';

/**
 * SmsService - Service for SMS operations using Twilio API
 *
 * This service provides SMS functionality including:
 * - Phone number verification (OTP via SMS)
 * - SMS message sending
 * - Twilio API integration with proper error handling
 *
 * Features:
 * - Phone number verification with OTP
 * - General SMS message delivery
 * - Environment-based configuration
 * - Comprehensive error handling
 *
 * @see https://www.twilio.com/docs/verify/api
 * @see https://www.twilio.com/docs/sms/api/message-resource
 *
 * @example
 * // Initiate phone verification
 * await smsService.initiatePhoneNumberVerification('+1234567890');
 *
 * @example
 * // Confirm verification code
 * const isValid = await smsService.confirmPhoneNumber('+1234567890', '123456');
 *
 * @example
 * // Send SMS message
 * await smsService.sendMessage('+1234567890', 'Your appointment is confirmed!');
 */
@Injectable()
export default class SmsService {
  private readonly logger = new Logger(SmsService.name);
  private twilioClient: Twilio;

  constructor(private readonly configService: ConfigService) {
    // Initialize Twilio client with credentials from environment
    const accountSid = configService.get('TWILIO_ACCOUNT_SID') as string;
    const authToken = configService.get('TWILIO_AUTH_TOKEN') as string;

    // Validate required configuration
    if (!accountSid || !authToken) {
      this.logger.error('Twilio credentials missing in environment variables');
      throw new Error('Twilio configuration incomplete');
    }

    this.twilioClient = new Twilio(accountSid, authToken);
  }

  /**
   * Initiates phone number verification via SMS OTP
   *
   * Sends a verification code (OTP) to the specified phone number
   * using Twilio Verify service. This is typically used for:
   * - User registration phone verification
   * - Two-factor authentication (2FA)
   * - Phone number updates
   *
   * @param phoneNumber - Phone number in E.164 format (e.g., +1234567890)
   * @returns Twilio verification object
   *
   * @throws Error if Twilio API call fails
   * @throws Error if configuration is missing
   *
   * @note Phone number must be in E.164 format
   * @note Consider rate limiting to prevent abuse
   * @note Log successful/failed attempts for audit
   */
  initiatePhoneNumberVerification(phoneNumber: string) {
    const serviceSid = this.configService.get<string>(
      'TWILIO_VERIFICATION_SERVICE_SID',
    ) as string;

    // Validate configuration
    if (!serviceSid) {
      throw new Error('Twilio Verification Service SID not configured');
    }

    this.logger.log(`Initiating phone verification for: ${phoneNumber}`);

    return this.twilioClient.verify.v2
      .services(serviceSid)
      .verifications.create({
        to: phoneNumber,
        channel: 'sms', // Options: 'sms', 'call', 'email'
      });
  }

  /**
   * Confirms a phone number verification code
   *
   * Validates the OTP entered by the user against the code sent by Twilio.
   * Returns true if verification is successful, throws exception otherwise.
   *
   * @param phoneNumber - Phone number in E.164 format (same as used in initiation)
   * @param verificationCode - OTP code received by user (typically 6 digits)
   * @returns true if verification is successful
   *
   * @throws BadRequestException if code is invalid or verification failed
   * @throws Error if Twilio API call fails
   *
   * @note Consider adding expiration check (codes typically expire after 10 minutes)
   * @note Implement rate limiting for verification attempts
   */
  async confirmPhoneNumber(
    phoneNumber: string,
    verificationCode: string,
  ): Promise<boolean> {
    const serviceSid = this.configService.get(
      'TWILIO_VERIFICATION_SERVICE_SID',
    ) as string;

    // Validate configuration
    if (!serviceSid) {
      throw new Error('Twilio Verification Service SID not configured');
    }

    this.logger.log(`Confirming verification for: ${phoneNumber}`);

    try {
      const result = await this.twilioClient.verify.v2
        .services(serviceSid)
        .verificationChecks.create({
          to: phoneNumber,
          code: verificationCode,
        });

      // Check verification result
      if (!result.valid || result.status !== 'approved') {
        this.logger.warn(`Invalid verification code for: ${phoneNumber}`);
        throw new BadRequestException('Wrong code provided');
      }

      this.logger.log(`Phone verification successful for: ${phoneNumber}`);
      return true;
    } catch (error) {
      this.logger.error(`Verification failed for ${phoneNumber}:`, error);

      // Re-throw BadRequestException, wrap other errors
      if (error instanceof BadRequestException) {
        throw error;
      }
      throw new BadRequestException('Verification failed. Please try again.');
    }
  }

  /**
   * Sends an SMS message to a phone number
   *
   * Delivers an SMS message using Twilio's messaging service.
   * Can be used for notifications, alerts, or general communication.
   *
   * @param receiverPhoneNumber - Recipient phone number in E.164 format
   * @param message - SMS message content (max 1600 characters)
   * @returns Twilio message object
   *
   * @throws Error if Twilio API call fails
   * @throws Error if configuration is missing
   *
   * @note Message length affects cost (segmented messages for >160 chars)
   * @note Consider content filtering for compliance
   * @note Log message delivery for audit purposes
   */
  async sendMessage(receiverPhoneNumber: string, message: string) {
    const senderPhoneNumber = this.configService.get(
      'TWILIO_SENDER_PHONE_NUMBER',
    ) as string;

    // Validate configuration
    if (!senderPhoneNumber) {
      throw new Error('Twilio sender phone number not configured');
    }

    this.logger.log(`Sending SMS to: ${receiverPhoneNumber}`);

    return this.twilioClient.messages.create({
      body: message,
      from: senderPhoneNumber,
      to: receiverPhoneNumber,
      // Additional options:
      // statusCallback: 'https://your-domain.com/sms-status', // Delivery status webhook
      // maxPrice: 0.05, // Maximum price in USD
    });
  }

  /**
   * Enhanced methods that could be added:
   *
   * async sendBulkMessages(phoneNumbers: string[], message: string): Promise<void> {
   *   // Send same message to multiple recipients efficiently
   * }
   *
   * async checkMessageStatus(messageSid: string): Promise<any> {
   *   // Check delivery status of a sent message
   * }
   *
   * async scheduleMessage(phoneNumber: string, message: string, sendAt: Date): Promise<any> {
   *   // Schedule SMS for future delivery
   * }
   *
   * validatePhoneNumber(phoneNumber: string): boolean {
   *   // Validate phone number format before sending
   * }
   */
}
