/*
|--------------------------------------------------------------------------
| Agência PSI — Edge Functions: helper schema-per-tenant
|--------------------------------------------------------------------------
| As tabelas tenant-scoped vivem em schemas físicos `tenant_<slug>` SEM a
| coluna tenant_id (docs/F0_categorizacao.md). Edge functions resolvem o
| schema a partir do tenant_id (que já chega via URL/body/linha) e usam
| `tdb.from(...)` para tabelas tenant. Tabelas GLOBAIS (tenants,
| tenant_members, profiles, subscriptions, addon_*, whatsapp_credit_*,
| channel_routing, audit_logs...) e RPCs continuam via o client público.
|
| Como edge functions usam service_role, `.schema(x)` exige que o schema
| esteja exposto no PostgREST (config.toml, F5). Schemas tenant entram lá
| na criação do tenant.
|--------------------------------------------------------------------------
*/
import { createClient, type SupabaseClient } from 'https://esm.sh/@supabase/supabase-js@2'

/** Espelha public.tenant_schema_name(slug). */
export function tenantSchemaName(slug: string | null | undefined): string | null {
    if (typeof slug !== 'string') return null
    if (!/^[a-z][a-z0-9_]{1,47}$/.test(slug)) return null
    return `tenant_${slug}`
}

/** Client service_role no schema public (tabelas globais + RPCs). */
export function adminClient(): SupabaseClient {
    return createClient(
        Deno.env.get('SUPABASE_URL')!,
        Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,
    )
}

/** tenant_id -> nome do schema (via tenants.slug). null se não existir. */
export async function schemaForTenant(admin: SupabaseClient, tenantId: string): Promise<string | null> {
    if (!tenantId) return null
    const { data, error } = await admin.from('tenants').select('slug').eq('id', tenantId).maybeSingle()
    if (error) {
        console.error('[tenant] schemaForTenant erro:', error.message)
        return null
    }
    return tenantSchemaName(data?.slug ?? null)
}

/**
 * tenant_id -> client ligado ao schema do tenant (para tabelas tenant).
 * Lança se o tenant não existir/sem slug — chamar tabela tenant sem schema é bug.
 */
export async function tenantDbForId(admin: SupabaseClient, tenantId: string): Promise<SupabaseClient> {
    const schema = await schemaForTenant(admin, tenantId)
    if (!schema) throw new Error(`[tenant] schema indisponível para tenant ${tenantId}`)
    return admin.schema(schema)
}

export type TenantRef = { tenantId: string; slug: string; schema: string }

/** Lista tenants ativos com schema provisionado — base dos crons que varrem todos. */
export async function listTenantSchemas(admin: SupabaseClient): Promise<TenantRef[]> {
    // tenant_schemas é populada por clone_tenant_template (F1/F2); join garante slug atual
    const { data, error } = await admin
        .from('tenant_schemas')
        .select('tenant_id, schema_name, tenants!inner(slug)')
    if (error) {
        console.error('[tenant] listTenantSchemas erro:', error.message)
        return []
    }
    return (data ?? [])
        .map((r: Record<string, unknown>) => {
            const slug = (r.tenants as { slug?: string } | null)?.slug ?? null
            const schema = tenantSchemaName(slug)
            return schema ? { tenantId: r.tenant_id as string, slug: slug as string, schema } : null
        })
        .filter((x): x is TenantRef => x !== null)
}

/**
 * Roteia um webhook inbound -> tenant, via public.channel_routing.
 * Usado quando a function NÃO recebe tenant_id na URL (ex.: Meta Cloud API,
 * que identifica o canal por phone_number_id). Os webhooks Twilio/Evolution
 * deste projeto recebem tenant_id na própria URL e NÃO precisam disto.
 */
export async function resolveTenantByChannel(
    admin: SupabaseClient,
    keys: { senderAddress?: string | null; twilioPhone?: string | null; twilioSid?: string | null },
): Promise<(TenantRef & { channelId: string }) | null> {
    let q = admin.from('channel_routing').select('channel_id, tenant_id, tenants!inner(slug)').limit(1)
    if (keys.twilioSid) q = q.eq('twilio_subaccount_sid', keys.twilioSid)
    else if (keys.twilioPhone) q = q.eq('twilio_phone_number', keys.twilioPhone)
    else if (keys.senderAddress) q = q.eq('sender_address', keys.senderAddress)
    else return null

    const { data, error } = await q.maybeSingle()
    if (error || !data) {
        if (error) console.error('[tenant] resolveTenantByChannel erro:', error.message)
        return null
    }
    const slug = (data.tenants as { slug?: string } | null)?.slug ?? null
    const schema = tenantSchemaName(slug)
    if (!schema) return null
    return { tenantId: data.tenant_id as string, slug: slug as string, schema, channelId: data.channel_id as string }
}
