import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
  ChannelAdapterPort,
  SendMessageParams,
  DeliveryResult,
} from '../../domain/ports/outbound/channel-adapter.port';
import { ChannelType } from '../../domain/value-objects/channel-type.vo';
import { randomUUID } from 'crypto';

@Injectable()
export class VoiceCallAdapter implements ChannelAdapterPort {
  private readonly logger = new Logger(VoiceCallAdapter.name);
  readonly channelType = ChannelType.VOICE_CALL;

  constructor(private readonly config: ConfigService) {}

  async send(params: SendMessageParams): Promise<DeliveryResult> {
    const accountSid = this.config.get<string>('TWILIO_ACCOUNT_SID');
    const authToken = this.config.get<string>('TWILIO_AUTH_TOKEN');
    const fromNumber = this.config.get<string>('TWILIO_FROM_NUMBER');

    try {
      const url = `https://api.twilio.com/2010-04-01/Accounts/${accountSid}/Calls.json`;
      const credentials = Buffer.from(`${accountSid}:${authToken}`).toString('base64');

      const twiml = `<Response><Say language="zh-CN">${this.escapeXml(params.ttsText ?? params.content)}</Say></Response>`;

      const body = new URLSearchParams({
        To: params.to.phone!,
        From: fromNumber!,
        Twiml: twiml,
      });

      const response = await fetch(url, {
        method: 'POST',
        headers: {
          Authorization: `Basic ${credentials}`,
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: body.toString(),
      });

      if (!response.ok) {
        const errorData = await response.text();
        throw new Error(`Twilio Voice error: ${response.status} ${errorData}`);
      }

      const data = await response.json();
      return { messageId: data.sid ?? randomUUID(), status: 'sent' };
    } catch (error) {
      this.logger.error('Voice call failed', error);
      return {
        messageId: randomUUID(),
        status: 'failed',
        error: error instanceof Error ? error.message : 'Voice call failed',
      };
    }
  }

  async isAvailable(): Promise<boolean> {
    return !!(
      this.config.get('TWILIO_ACCOUNT_SID') &&
      this.config.get('TWILIO_AUTH_TOKEN') &&
      this.config.get('TWILIO_FROM_NUMBER')
    );
  }

  private escapeXml(text: string): string {
    return text
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&apos;');
  }
}
