/**
 * Twilio WhatsApp Service
 *
 * Handles Twilio WhatsApp messaging: signature validation, message parsing,
 * sending text/payment-link messages, and credential management.
 */

import twilio from 'twilio';
import { validateRequest } from 'twilio/lib/webhooks/webhooks';
import { logger } from '@/lib/logger';
import { decrypt } from '@/lib/encryption';
import { organizationsAdapter } from '@/lib/adapters/organizations';
import type {
  TwilioWhatsAppCredentials,
  TwilioSendResult,
  TwilioIncomingMessage,
} from '@/lib/types/twilio-whatsapp.types';

class TwilioWhatsAppService {
  /**
   * Validate an incoming Twilio webhook signature
   */
  validateSignature(
    authToken: string,
    signature: string,
    url: string,
    params: Record<string, string>
  ): boolean {
    try {
      return validateRequest(authToken, signature, url, params);
    } catch (error) {
      logger.error('Twilio signature validation error', { error });
      return false;
    }
  }

  /**
   * Parse an incoming Twilio WhatsApp message from form data
   */
  parseIncomingMessage(formData: URLSearchParams): TwilioIncomingMessage {
    const numMedia = parseInt(formData.get('NumMedia') || '0', 10);

    const mediaUrls: string[] = [];
    const mediaContentTypes: string[] = [];

    for (let i = 0; i < numMedia; i++) {
      const url = formData.get(`MediaUrl${i}`);
      const type = formData.get(`MediaContentType${i}`);
      if (url) mediaUrls.push(url);
      if (type) mediaContentTypes.push(type);
    }

    return {
      messageSid: formData.get('MessageSid') || '',
      from: formData.get('From') || '',
      to: formData.get('To') || '',
      body: formData.get('Body') || '',
      numMedia,
      mediaUrls,
      mediaContentTypes,
      profileName: formData.get('ProfileName') || undefined,
    };
  }

  /**
   * Send a text message via Twilio WhatsApp
   */
  async sendTextMessage(
    credentials: TwilioWhatsAppCredentials,
    to: string,
    body: string
  ): Promise<TwilioSendResult> {
    try {
      const client = twilio(credentials.accountSid, credentials.authToken);

      const message = await client.messages.create({
        from: `whatsapp:${credentials.whatsappNumber}`,
        to,
        body,
      });

      logger.info('WhatsApp message sent', {
        messageSid: message.sid,
        to,
      });

      return { success: true, messageSid: message.sid };
    } catch (error) {
      const errorMessage =
        error instanceof Error ? error.message : 'Failed to send message';
      logger.error('Failed to send WhatsApp message', { to, error });
      return { success: false, error: errorMessage };
    }
  }

  /**
   * Send a payment link message with booking details
   */
  async sendPaymentLink(
    credentials: TwilioWhatsAppCredentials,
    to: string,
    bookingDetails: { service: string; amount: number; currency: string },
    paymentUrl: string
  ): Promise<TwilioSendResult> {
    const body = [
      `Your booking for *${bookingDetails.service}* requires a deposit.`,
      '',
      `Amount: ${bookingDetails.currency} ${bookingDetails.amount.toFixed(2)}`,
      '',
      `Pay securely here: ${paymentUrl}`,
      '',
      'This link expires in 30 minutes.',
    ].join('\n');

    return this.sendTextMessage(credentials, to, body);
  }

  /**
   * Get decrypted Twilio credentials for an organization
   */
  async getCredentialsForOrg(
    orgId: string
  ): Promise<TwilioWhatsAppCredentials | null> {
    try {
      const org = await organizationsAdapter.findUnique({
        where: { id: orgId },
        select: {
          twilioAccountSid: true,
          twilioAuthTokenEncrypted: true,
          twilioWhatsappNumber: true,
        },
      });

      const orgRecord = org as Record<string, unknown> | null;
      if (
        !orgRecord ||
        !orgRecord.twilioAccountSid ||
        !orgRecord.twilioAuthTokenEncrypted ||
        !orgRecord.twilioWhatsappNumber
      ) {
        return null;
      }

      return {
        accountSid: orgRecord.twilioAccountSid as string,
        authToken: decrypt(orgRecord.twilioAuthTokenEncrypted as string),
        whatsappNumber: orgRecord.twilioWhatsappNumber as string,
      };
    } catch (error) {
      logger.error('Failed to get Twilio credentials for org', {
        orgId,
        error,
      });
      return null;
    }
  }

  /**
   * Look up an organization by its Twilio WhatsApp number
   */
  async getOrgByTwilioNumber(
    twilioNumber: string
  ): Promise<{ id: string; name: string; ownerId: string } | null> {
    try {
      const org = await organizationsAdapter.findFirst({
        where: { twilioWhatsappNumber: twilioNumber },
      });
      if (!org) return null;
      const r = org as Record<string, unknown>;
      return { id: r.id as string, name: r.name as string, ownerId: r.ownerId as string };
    } catch (error) {
      logger.error('Failed to look up org by Twilio number', {
        twilioNumber,
        error,
      });
      return null;
    }
  }
}

export const twilioWhatsAppService = new TwilioWhatsAppService();
