/**
 * Phoenix Messaging Orchestrator Service
 * Multi-provider messaging (SMS/voice/email/push) with failover
 */

import { getDb } from '../../db/index.js'
import { logger } from '../../lib/logger.js'

export interface MessageRequest {
  channel: 'SMS' | 'EMAIL' | 'VOICE' | 'PUSH'
  to: string
  template: string
  params: Record<string, any>
  priority: 'LOW' | 'NORMAL' | 'HIGH'
}

export interface MessageStatus {
  messageId: string
  status: 'PENDING' | 'SENT' | 'DELIVERED' | 'FAILED'
  provider: string
  deliveryReceipt?: any
  retryCount: number
}

class MessagingOrchestratorService {
  /**
   * Send a message with provider routing and failover
   */
  async sendMessage(request: MessageRequest): Promise<MessageStatus> {
    const db = getDb()
    
    // Select provider based on rules (cost, deliverability, region, user preference)
    const provider = await this.selectProvider(request)
    
    const result = await db.query(
      `INSERT INTO messages (channel, recipient, template, params, priority, provider, status)
       VALUES ($1, $2, $3, $4, $5, $6, 'PENDING')
       RETURNING *`,
      [
        request.channel,
        request.to,
        request.template,
        JSON.stringify(request.params),
        request.priority,
        provider
      ]
    )

    const messageId = result.rows[0].id

    try {
      // Send via provider adapter
      await this.sendViaProvider(provider, request)
      
      await db.query(
        `UPDATE messages SET status = 'SENT' WHERE id = $1`,
        [messageId]
      )

      logger.info('Message sent', { messageId, provider })
      return {
        messageId,
        status: 'SENT',
        provider,
        retryCount: 0
      }
    } catch (error) {
      // Try failover provider
      const failoverProvider = await this.selectFailoverProvider(request, provider)
      
      if (failoverProvider) {
        logger.info('Retrying with failover provider', { messageId, failoverProvider })
        return this.sendMessage({ ...request, priority: 'HIGH' })
      }

      await db.query(
        `UPDATE messages SET status = 'FAILED' WHERE id = $1`,
        [messageId]
      )

      throw error
    }
  }

  /**
   * Get message status
   */
  async getMessageStatus(messageId: string): Promise<MessageStatus> {
    const db = getDb()
    
    const result = await db.query(
      `SELECT * FROM messages WHERE id = $1`,
      [messageId]
    )

    if (result.rows.length === 0) {
      throw new Error('Message not found')
    }

    const row = result.rows[0]
    return {
      messageId: row.id,
      status: row.status,
      provider: row.provider,
      deliveryReceipt: row.delivery_receipt,
      retryCount: row.retry_count || 0
    }
  }

  private async selectProvider(request: MessageRequest): Promise<string> {
    // Provider selection logic based on cost, deliverability, region, user preference
    // Placeholder - would implement actual routing rules
    const providers: Record<string, string[]> = {
      SMS: ['twilio', 'aws-sns', 'vonage'],
      EMAIL: ['aws-ses', 'sendgrid'],
      VOICE: ['twilio', 'vonage'],
      PUSH: ['fcm', 'apns']
    }

    return providers[request.channel]?.[0] || 'twilio'
  }

  private async selectFailoverProvider(request: MessageRequest, failedProvider: string): Promise<string | null> {
    // Select next provider in failover chain
    const providers: Record<string, string[]> = {
      SMS: ['twilio', 'aws-sns', 'vonage'],
      EMAIL: ['aws-ses', 'sendgrid'],
      VOICE: ['twilio', 'vonage'],
      PUSH: ['fcm', 'apns']
    }

    const chain = providers[request.channel] || []
    const index = chain.indexOf(failedProvider)
    return index >= 0 && index < chain.length - 1 ? chain[index + 1] : null
  }

  private async sendViaProvider(provider: string, request: MessageRequest): Promise<void> {
    // This would call the appropriate provider adapter
    logger.info('Sending via provider', { provider, request })
    // Placeholder - would implement actual provider calls
  }
}

export const messagingOrchestratorService = new MessagingOrchestratorService()
