/*
|--------------------------------------------------------------------------
| Agência PSI — Edge Function: twilio-whatsapp-inbound
|--------------------------------------------------------------------------
| Recebe mensagens WhatsApp RECEBIDAS pelos tenants via Twilio.
| Diferente do twilio-whatsapp-webhook (que trata apenas status de mensagens
| enviadas), este recebe o conteudo de respostas dos pacientes.
|
| URL configurada no numero da subconta de cada tenant, campo "WHEN A
| MESSAGE COMES IN":
|   https://<project>.supabase.co/functions/v1/twilio-whatsapp-inbound?tenant_id=<uuid>
|
| Hooks aplicados (provider-agnostico via _shared/whatsapp-hooks):
|   1) Opt-IN detection (keywords "voltar", "retornar", ...)
|   2) Opt-OUT detection (keywords do tenant + system) com ack automatico
|   3) Auto-reply fora do horario (se nao houve opt-out) com credit deduction
|
| Custos: cada envio (ack de opt-out + auto-reply) DEDUZ 1 credito do tenant.
| Se o saldo estiver zerado, o hook falha silenciosamente (nao envia).
|--------------------------------------------------------------------------
*/

import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
import {
    buildThreadKey,
    detectOptoutKeyword,
    maybeOptIn,
    maybeProcessBot,
    maybeSendAutoReply,
    makeTwilioCreditedSendFn,
    registerOptout,
    type TwilioChannel
} from '../_shared/whatsapp-hooks.ts'
import { tenantDbForId } from '../_shared/tenant.ts'

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

const EMPTY_TWIML = '<?xml version="1.0" encoding="UTF-8"?><Response></Response>'

function stripWhatsappPrefix(raw: string | null | undefined): string | null {
    if (!raw) return null
    return raw.replace(/^whatsapp:/i, '').trim()
}

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

    if (req.method !== 'POST') {
        return new Response(EMPTY_TWIML, {
            status: 200,
            headers: { ...corsHeaders, 'Content-Type': 'text/xml' }
        })
    }

    try {
        const url = new URL(req.url)
        const tenantId = url.searchParams.get('tenant_id')

        if (!tenantId) {
            console.error('[twilio-whatsapp-inbound] tenant_id ausente na URL')
            return new Response(EMPTY_TWIML, {
                status: 200,
                headers: { ...corsHeaders, 'Content-Type': 'text/xml' }
            })
        }

        const supabase = createClient(
            Deno.env.get('SUPABASE_URL')!,
            Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
        )
        const tdb = await tenantDbForId(supabase, tenantId)

        const formData = await req.formData()
        const from        = stripWhatsappPrefix(formData.get('From') as string)
        const to          = stripWhatsappPrefix(formData.get('To') as string)
        const body        = (formData.get('Body') as string) ?? null
        const messageSid  = formData.get('MessageSid') as string
        const numMedia    = parseInt((formData.get('NumMedia') as string) ?? '0', 10)
        const mediaUrl    = numMedia > 0 ? (formData.get('MediaUrl0') as string) : null
        const mediaMime   = numMedia > 0 ? (formData.get('MediaContentType0') as string) : null

        if (!from || !messageSid) {
            console.warn('[twilio-whatsapp-inbound] payload incompleto')
            return new Response(EMPTY_TWIML, {
                status: 200,
                headers: { ...corsHeaders, 'Content-Type': 'text/xml' }
            })
        }

        const cleanBody = body
            ? String(body).replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '').slice(0, 4000)
            : null

        const { data: matchData } = await supabase.rpc('match_patient_by_phone', {
            p_tenant_id: tenantId,
            p_phone: from
        })
        const patientId = matchData as string | null

        const raw: Record<string, unknown> = {
            MessageSid: messageSid,
            AccountSid: formData.get('AccountSid') ?? null,
            From: from,
            To: to,
            NumMedia: numMedia,
            ProfileName: formData.get('ProfileName') ?? null,
            WaId: formData.get('WaId') ?? null,
        }

        const { error: insErr } = await tdb.from('conversation_messages').insert({
            patient_id: patientId,
            channel: 'whatsapp',
            direction: 'inbound',
            from_number: from,
            to_number: to,
            body: cleanBody,
            media_url: mediaUrl,
            media_mime: mediaMime,
            provider: 'twilio',
            provider_message_id: messageSid,
            provider_raw: raw,
            kanban_status: 'awaiting_us',
            received_at: new Date().toISOString()
        })

        if (insErr) {
            console.error('[twilio-whatsapp-inbound] insert error:', insErr)
            return new Response(EMPTY_TWIML, {
                status: 200,
                headers: { ...corsHeaders, 'Content-Type': 'text/xml' }
            })
        }

        // ─────────────────────────────────────────────────────
        // Hooks: opt-in, opt-out, auto-reply
        // ─────────────────────────────────────────────────────
        let optoutAction: 'in' | 'out' | null = null
        let autoReplyResult: { sent: boolean; reason?: string } | null = null

        try {
            // Busca canal Twilio (uma vez) — reutilizado por registerOptout/autoReply
            const { data: channel } = await tdb
                .from('notification_channels')
                .select('credentials, provider, twilio_subaccount_sid, twilio_phone_number, is_active')
                .eq('channel', 'whatsapp')
                .is('deleted_at', null)
                .maybeSingle()

            if (channel && channel.is_active && channel.provider === 'twilio') {
                // 1) Opt-IN (voltar) tem prioridade
                if (await maybeOptIn(tdb, from, cleanBody)) {
                    optoutAction = 'in'
                }

                // 2) Opt-OUT por keyword — envia ack via Twilio (deduz 1 credito)
                if (!optoutAction) {
                    const keyword = await detectOptoutKeyword(tdb, cleanBody)
                    if (keyword) {
                        const optoutSendFn = makeTwilioCreditedSendFn(
                            supabase,
                            tenantId,
                            channel as unknown as TwilioChannel,
                            'Opt-out ack WhatsApp'
                        )
                        await registerOptout(
                            tdb,
                            from,
                            patientId,
                            cleanBody,
                            keyword,
                            'twilio',
                            optoutSendFn
                        )
                        optoutAction = 'out'
                    }
                }

                // 3) Bot de triagem (tem precedência sobre auto-reply)
                let botProcessed = false
                if (optoutAction !== 'out') {
                    const threadKey = buildThreadKey(patientId, from)
                    const botSendFn = makeTwilioCreditedSendFn(
                        supabase,
                        tenantId,
                        channel as unknown as TwilioChannel,
                        'Bot de triagem WhatsApp'
                    )
                    const botRes = await maybeProcessBot(
                        tdb,
                        supabase,
                        tenantId,
                        threadKey,
                        patientId,
                        from,
                        body,
                        botSendFn
                    )
                    botProcessed = !!botRes.processed
                }

                // 4) Auto-reply fora do horario (só se não foi opt-out nem bot)
                if (optoutAction !== 'out' && !botProcessed) {
                    const threadKey = buildThreadKey(patientId, from)
                    const arSendFn = makeTwilioCreditedSendFn(
                        supabase,
                        tenantId,
                        channel as unknown as TwilioChannel,
                        'Auto-reply WhatsApp'
                    )
                    autoReplyResult = await maybeSendAutoReply(
                        tdb,
                        threadKey,
                        from,
                        'twilio',
                        arSendFn
                    )
                }
            }
        } catch (err) {
            console.error('[twilio-whatsapp-inbound] hooks error:', err)
        }

        // Twilio espera TwiML vazio (nao reenvia); logs no console
        console.log('[twilio-whatsapp-inbound] processed', { tenantId, from, optoutAction, autoReplyResult })

        return new Response(EMPTY_TWIML, {
            status: 200,
            headers: { ...corsHeaders, 'Content-Type': 'text/xml' }
        })
    } catch (err) {
        console.error('[twilio-whatsapp-inbound] fatal:', err)
        return new Response(EMPTY_TWIML, {
            status: 200,
            headers: { ...corsHeaders, 'Content-Type': 'text/xml' }
        })
    }
})
