/*
|--------------------------------------------------------------------------
| Agência PSI — Edge Function: process-whatsapp-queue
|--------------------------------------------------------------------------
| Processa a notification_queue para channel='whatsapp' e provider='twilio'.
| Usa credenciais da SUBCONTA de cada tenant (modelo de subcontas).
|
| Fluxo:
|   1. Busca itens pendentes (channel='whatsapp', status='pendente')
|   2. Filtra somente tenants com provider='twilio' em notification_channels
|   3. Lock otimista (status → processando)
|   4. Resolve template (tenant → global fallback)
|   5. Renderiza variáveis {{var}}
|   6. Envia via Twilio usando credenciais da SUBCONTA do tenant
|   7. Atualiza queue + insere notification_logs com estimated_cost_brl
|   8. Retry com backoff em caso de erro
|--------------------------------------------------------------------------
*/

import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'

const corsHeaders = {
  'Access-Control-Allow-Origin':  '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
  'Access-Control-Allow-Methods': 'POST, OPTIONS',
}

// ── Template renderer ──────────────────────────────────────────────────────

function renderTemplate(template: string, variables: Record<string, unknown>): string {
  if (!template) return ''
  return template.replace(/\{\{([\w.]+)\}\}/g, (_, key) => {
    const val = variables[key]
    return val !== undefined && val !== null ? String(val) : ''
  })
}

// ── Twilio WhatsApp sender (via subconta) ─────────────────────────────────

async function sendWhatsAppViaTwilio(
  subAccountSid: string,
  subAuthToken:  string,
  fromNumber:    string,
  toNumber:      string,
  body:          string
): Promise<{ sid: string; status: string }> {
  const url  = `https://api.twilio.com/2010-04-01/Accounts/${subAccountSid}/Messages.json`
  const auth = btoa(`${subAccountSid}:${subAuthToken}`)

  const params = new URLSearchParams()
  params.set('From', `whatsapp:${fromNumber}`)
  params.set('To',   `whatsapp:${toNumber}`)
  params.set('Body', body)

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

  const data = await res.json()
  if (!res.ok) {
    throw new Error(data.message || `Twilio error ${res.status}: ${data.code}`)
  }

  return { sid: data.sid, status: data.status }
}

// ── Mock sender ────────────────────────────────────────────────────────────

function isMockMode(): boolean {
  const sid = Deno.env.get('TWILIO_ACCOUNT_SID') || ''
  return sid.startsWith('AC_TEST') || Deno.env.get('DEV') === 'true'
}

function mockSend(to: string, body: string): { sid: string; status: string } {
  const sid = `mock_wa_${crypto.randomUUID().slice(0, 8)}`
  console.log(`[WA MOCK] To: ${to} | Body: ${body} | SID: ${sid}`)
  return { sid, status: 'sent' }
}

// ── Main handler ──────────────────────────────────────────────────────────

Deno.serve(async (req: Request) => {
  if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders })

  const supabase = createClient(
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
  )

  const usdBrlRate = parseFloat(Deno.env.get('USD_BRL_RATE') ?? '5.5')

  const now = new Date().toISOString()

  // 1. Busca itens pendentes de WhatsApp
  const { data: items, error: fetchErr } = await supabase
    .from('notification_queue')
    .select('*')
    .eq('channel',  'whatsapp')
    .eq('status',   'pendente')
    .lte('scheduled_at', now)
    .order('scheduled_at', { ascending: true })
    .limit(20)

  if (fetchErr) {
    return new Response(
      JSON.stringify({ error: fetchErr.message }),
      { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
    )
  }

  if (!items?.length) {
    return new Response(
      JSON.stringify({ message: 'Nenhuma mensagem WhatsApp na fila', processed: 0 }),
      { status: 200, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
    )
  }

  // Cache de canais por tenant para evitar N+1
  const channelCache: Record<string, {
    twilio_subaccount_sid: string
    twilio_phone_number:   string
    cost_per_message_usd:  number
    price_per_message_brl: number
    credentials:           Record<string, string>
  } | null> = {}

  async function getChannel(tenantId: string) {
    if (tenantId in channelCache) return channelCache[tenantId]
    const { data } = await supabase
      .from('notification_channels')
      .select('twilio_subaccount_sid, twilio_phone_number, cost_per_message_usd, price_per_message_brl, credentials')
      .eq('tenant_id', tenantId)
      .eq('channel',   'whatsapp')
      .eq('provider',  'twilio')
      .eq('is_active', true)
      .is('deleted_at', null)
      .maybeSingle()
    channelCache[tenantId] = data
    return data
  }

  const results: Array<{ id: string; status: string; error?: string }> = []

  for (const item of items) {
    if (item.attempts >= (item.max_attempts || 5)) continue

    // 2. Lock otimista
    const { error: lockErr } = await supabase
      .from('notification_queue')
      .update({ status: 'processando', attempts: item.attempts + 1 })
      .eq('id',     item.id)
      .eq('status', 'pendente')

    if (lockErr) {
      results.push({ id: item.id, status: 'skip', error: 'lock failed' })
      continue
    }

    try {
      // 3. Busca canal twilio do tenant
      const channel = await getChannel(item.tenant_id)
      if (!channel?.twilio_subaccount_sid) {
        throw new Error('Tenant não tem subconta Twilio WhatsApp ativa')
      }

      const subToken = channel.credentials?.subaccount_auth_token
      if (!subToken) throw new Error('subaccount_auth_token não encontrado nas credenciais')

      // 4. Resolve template: tenant → global fallback
      let template: { body_text: string } | null = null

      const { data: tenantTpl } = await supabase
        .from('notification_templates')
        .select('body_text')
        .eq('tenant_id', item.tenant_id)
        .eq('key',       item.template_key)
        .eq('channel',   'whatsapp')
        .eq('is_active', true)
        .is('deleted_at', null)
        .maybeSingle()

      if (tenantTpl) {
        template = tenantTpl
      } else {
        const { data: globalTpl } = await supabase
          .from('notification_templates')
          .select('body_text')
          .is('tenant_id', null)
          .eq('key',        item.template_key)
          .eq('channel',    'whatsapp')
          .eq('is_default', true)
          .eq('is_active',  true)
          .is('deleted_at', null)
          .maybeSingle()
        template = globalTpl
      }

      if (!template) throw new Error(`Template WhatsApp não encontrado: ${item.template_key}`)

      // 5. Renderiza variáveis
      const vars    = item.resolved_vars || {}
      const message = renderTemplate(template.body_text, vars)

      // 6. Envia via Twilio (subconta do tenant)
      let sendResult: { sid: string; status: string }

      if (isMockMode()) {
        sendResult = mockSend(item.recipient_address, message)
      } else {
        sendResult = await sendWhatsAppViaTwilio(
          channel.twilio_subaccount_sid,
          subToken,
          channel.twilio_phone_number,
          item.recipient_address,
          message
        )
      }

      // Custo estimado em BRL
      const costBrl = (channel.cost_per_message_usd ?? 0) * usdBrlRate

      // 7. Sucesso — atualiza fila
      await supabase
        .from('notification_queue')
        .update({
          status:              'enviado',
          sent_at:             new Date().toISOString(),
          provider_message_id: sendResult.sid,
        })
        .eq('id', item.id)

      // 7b. Insere no log
      await supabase.from('notification_logs').insert({
        tenant_id:           item.tenant_id,
        owner_id:            item.owner_id,
        queue_id:            item.id,
        agenda_evento_id:    item.agenda_evento_id,
        patient_id:          item.patient_id,
        channel:             'whatsapp',
        template_key:        item.template_key,
        schedule_key:        item.schedule_key,
        recipient_address:   item.recipient_address,
        resolved_message:    message,
        resolved_vars:       vars,
        status:              'sent',
        provider:            'twilio',
        provider_message_id: sendResult.sid,
        provider_status:     sendResult.status,
        estimated_cost_brl:  costBrl,
        sent_at:             new Date().toISOString(),
      })

      results.push({ id: item.id, status: 'enviado' })

    } catch (e) {
      // 8. Erro — retry com backoff exponencial
      const attempts    = item.attempts + 1
      const maxAttempts = item.max_attempts || 5
      const isExhausted = attempts >= maxAttempts
      const retryMs     = Math.min(attempts * 2 * 60 * 1000, 30 * 60 * 1000) // max 30min

      await supabase
        .from('notification_queue')
        .update({
          status:        isExhausted ? 'falhou' : 'pendente',
          last_error:    e.message,
          next_retry_at: isExhausted ? null : new Date(Date.now() + retryMs).toISOString(),
        })
        .eq('id', item.id)

      await supabase.from('notification_logs').insert({
        tenant_id:         item.tenant_id,
        owner_id:          item.owner_id,
        queue_id:          item.id,
        agenda_evento_id:  item.agenda_evento_id,
        patient_id:        item.patient_id,
        channel:           'whatsapp',
        template_key:      item.template_key,
        schedule_key:      item.schedule_key,
        recipient_address: item.recipient_address,
        status:            'failed',
        provider:          'twilio',
        failure_reason:    e.message,
        failed_at:         new Date().toISOString(),
      })

      results.push({ id: item.id, status: isExhausted ? 'falhou' : 'retry', error: e.message })
    }
  }

  const sent   = results.filter(r => r.status === 'enviado').length
  const failed = results.filter(r => r.status === 'falhou').length
  const retry  = results.filter(r => r.status === 'retry').length

  return new Response(
    JSON.stringify({ processed: results.length, sent, failed, retry, details: results }),
    { status: 200, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
  )
})
