/*
|--------------------------------------------------------------------------
| Agência PSI — Edge Function: submit-patient-intake (A#20 rev2)
|--------------------------------------------------------------------------
| Defesa em camadas SELF-HOSTED (substitui Turnstile):
|   1. Honeypot field            → frontend renderiza, edge rejeita se vier preenchido
|   2. Rate limit por IP         → check_rate_limit RPC
|   3. Math captcha CONDICIONAL  → exigido só após N falhas do mesmo IP
|   4. Logging                   → record_submission_attempt RPC (genérico)
|   5. Modo paranoid             → saas_security_config.captcha_required_globally
|
| Endpoints:
|   POST /                  → submit do form
|   POST /captcha-challenge → gera math challenge (id+question) sob demanda
|--------------------------------------------------------------------------
*/

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

const SUPABASE_URL          = Deno.env.get('SUPABASE_URL')
const SUPABASE_SERVICE_KEY  = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
const ENDPOINT_NAME         = 'patient_intake'

const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY)

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

function jsonResponse(body, status = 200) {
    return new Response(JSON.stringify(body), {
        status,
        headers: { 'content-type': 'application/json', ...CORS_HEADERS }
    })
}

// SHA-256 estável (rate limit é por hash, nunca pelo IP cru — privacidade)
async function hashIp(ip) {
    if (!ip) return null
    const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(`agenciapsi:${ip}`))
    return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, '0')).join('').slice(0, 32)
}

function getClientIp(req) {
    const xff = req.headers.get('x-forwarded-for')
    if (xff) return xff.split(',')[0].trim()
    return req.headers.get('cf-connecting-ip') || req.headers.get('x-real-ip') || null
}

// ─────────────────────────────────────────────────────────────────────────
// Handler principal
// -----------------------------------------------------------------------------
Deno.serve(async (req) => {
    if (req.method === 'OPTIONS') return new Response(null, { status: 204, headers: CORS_HEADERS })
    if (req.method !== 'POST')    return jsonResponse({ error: 'method-not-allowed' }, 405)

    const url = new URL(req.url)
    const isCaptchaEndpoint = url.pathname.endsWith('/captcha-challenge')

    // ── Endpoint de challenge (sem rate limit aqui pra não bloquear UX) ──
    if (isCaptchaEndpoint) {
        const { data, error } = await supabase.rpc('generate_math_challenge')
        if (error) return jsonResponse({ error: 'challenge-failed', message: error.message }, 500)
        return jsonResponse({ challenge: data }, 200)
    }

    // ── Endpoint principal: submit do intake ──
    let body
    try {
        body = await req.json()
    } catch {
        return jsonResponse({ error: 'invalid-json' }, 400)
    }

    const token        = String(body?.token || '').trim()
    const payload      = body?.payload && typeof body.payload === 'object' ? body.payload : null
    const honeypot     = String(body?.website || '').trim() // honeypot field name
    const captchaId    = body?.captcha_id ? String(body.captcha_id) : null
    const captchaAnswer = body?.captcha_answer != null ? Number(body.captcha_answer) : null
    const ip           = getClientIp(req)
    const ipHash       = await hashIp(ip)
    const userAgent    = String(body?.client_info || req.headers.get('user-agent') || '').slice(0, 500)

    // ── 1) HONEYPOT: bot tipicamente preenche todos os campos ──
    if (honeypot.length > 0) {
        await supabase.rpc('record_submission_attempt', {
            p_endpoint:   ENDPOINT_NAME,
            p_ip_hash:    ipHash,
            p_success:    false,
            p_blocked_by: 'honeypot',
            p_error_code: 'honeypot_filled',
            p_error_msg:  null,
            p_user_agent: userAgent,
            p_metadata:   null
        })
        // Resposta deliberadamente igual à de sucesso pra não dar feedback ao bot
        return jsonResponse({ ok: true, intake_id: null }, 200)
    }

    if (!token || !payload) {
        await supabase.rpc('record_submission_attempt', {
            p_endpoint:   ENDPOINT_NAME,
            p_ip_hash:    ipHash,
            p_success:    false,
            p_blocked_by: 'validation',
            p_error_code: 'missing_fields',
            p_error_msg:  null,
            p_user_agent: userAgent,
            p_metadata:   null
        })
        return jsonResponse({ error: 'missing-fields' }, 400)
    }

    // ── 2) RATE LIMIT + decisão de captcha ──
    const { data: rl, error: rlErr } = await supabase.rpc('check_rate_limit', {
        p_ip_hash:  ipHash,
        p_endpoint: ENDPOINT_NAME
    })
    if (rlErr) {
        // fail-open mas logado
        console.error('[submit-patient-intake] check_rate_limit failed:', rlErr.message)
    }

    if (rl && rl.allowed === false) {
        await supabase.rpc('record_submission_attempt', {
            p_endpoint:   ENDPOINT_NAME,
            p_ip_hash:    ipHash,
            p_success:    false,
            p_blocked_by: 'rate_limit',
            p_error_code: rl.reason || 'blocked',
            p_error_msg:  null,
            p_user_agent: userAgent,
            p_metadata:   null
        })
        return jsonResponse({
            error: 'rate-limited',
            retry_after_seconds: rl.retry_after_seconds || null
        }, 429)
    }

    // ── 3) MATH CAPTCHA condicional ──
    if (rl && rl.requires_captcha === true) {
        if (!captchaId || !Number.isFinite(captchaAnswer)) {
            await supabase.rpc('record_submission_attempt', {
                p_endpoint:   ENDPOINT_NAME,
                p_ip_hash:    ipHash,
                p_success:    false,
                p_blocked_by: 'captcha',
                p_error_code: 'captcha_required',
                p_error_msg:  null,
                p_user_agent: userAgent,
                p_metadata:   null
            })
            return jsonResponse({ error: 'captcha-required' }, 403)
        }

        const { data: ok, error: vErr } = await supabase.rpc('verify_math_challenge', {
            p_id:     captchaId,
            p_answer: captchaAnswer
        })
        if (vErr || !ok) {
            await supabase.rpc('record_submission_attempt', {
                p_endpoint:   ENDPOINT_NAME,
                p_ip_hash:    ipHash,
                p_success:    false,
                p_blocked_by: 'captcha',
                p_error_code: 'captcha_wrong',
                p_error_msg:  vErr?.message || null,
                p_user_agent: userAgent,
                p_metadata:   null
            })
            return jsonResponse({ error: 'captcha-wrong' }, 403)
        }
    }

    // ── 4) Chama RPC do intake ──
    const { data, error } = await supabase.rpc('create_patient_intake_request_v2', {
        p_token:       token,
        p_payload:     payload,
        p_client_info: userAgent || null
    })

    if (error) {
        await supabase.rpc('record_submission_attempt', {
            p_endpoint:   ENDPOINT_NAME,
            p_ip_hash:    ipHash,
            p_success:    false,
            p_blocked_by: 'rpc',
            p_error_code: error.code || 'rpc_err',
            p_error_msg:  error.message,
            p_user_agent: userAgent,
            p_metadata:   null
        })
        return jsonResponse({ error: 'rpc-failed', message: error.message }, 400)
    }

    await supabase.rpc('record_submission_attempt', {
        p_endpoint:   ENDPOINT_NAME,
        p_ip_hash:    ipHash,
        p_success:    true,
        p_blocked_by: null,
        p_error_code: null,
        p_error_msg:  null,
        p_user_agent: userAgent,
        p_metadata:   null
    })
    return jsonResponse({ ok: true, intake_id: data }, 200)
})
