/**
 * admin-gateway — cliente do painel unificado ByVulcan (admin.byvulcan.com).
 *
 * Espelha o padrão usado por Vulcan-Clerk, Vulcan-Organizer e Appoint:
 * todas as chamadas server-side passam pelo `VULCAN_ADMIN_URL` com header
 * `x-vulcan-secret` + `x-product-id`. Nenhuma chamada é bloqueante — todas
 * são fire-and-forget com timeout curto, devolvem `{ok:false}` quando o
 * admin está offline para o Vulcan-Music degradar com elegância.
 *
 * Endpoints implementados (referência: vulcanappsadmin/src/proxy.ts):
 *   POST /api/v1/entitlements/grant-default   — concede tier default
 *   POST /api/v1/credits/check                — checa saldo (não debita)
 *   POST /api/v1/credits/debit                — debita 1 crédito
 *   POST /api/v1/ai-usage                     — registra uso (cost=0)
 *   POST /api/v1/security/event               — audit log
 *   POST /api/users/change-plan               — sincroniza plano pós-pagamento
 *   POST /api/v1/oauth/{provider}/callback    — guarda tokens OAuth no cofre central
 *   GET  /api/v1/plans/public?product=...     — catálogo de planos
 */
import { env } from '../../env.js';
import { logger } from '../../logger.js';
const ADMIN_URL = env.VULCAN_ADMIN_URL;
const PLATFORM_SECRET = env.VULCAN_PLATFORM_SECRET;
const PRODUCT_ID = env.VULCAN_PRODUCT_ID;
function isConfigured() {
    return Boolean(ADMIN_URL && PLATFORM_SECRET);
}
function platformHeaders() {
    return {
        'Content-Type': 'application/json',
        'x-vulcan-secret': PLATFORM_SECRET ?? '',
        'x-product-id': PRODUCT_ID,
    };
}
async function postJSON(path, body, timeoutMs = 5000) {
    if (!isConfigured())
        return { ok: false, error: 'admin_not_configured' };
    try {
        const res = await fetch(`${ADMIN_URL}${path}`, {
            method: 'POST',
            headers: platformHeaders(),
            body: JSON.stringify(body),
            signal: AbortSignal.timeout(timeoutMs),
        });
        if (!res.ok) {
            const text = await res.text().catch(() => '');
            return { ok: false, status: res.status, error: text.slice(0, 200) || `HTTP ${res.status}` };
        }
        const data = (await res.json().catch(() => ({})));
        return { ok: true, data };
    }
    catch (err) {
        return { ok: false, error: err instanceof Error ? err.message : 'unknown' };
    }
}
async function getJSON(path, timeoutMs = 5000) {
    if (!isConfigured())
        return { ok: false, error: 'admin_not_configured' };
    try {
        const res = await fetch(`${ADMIN_URL}${path}`, {
            headers: platformHeaders(),
            signal: AbortSignal.timeout(timeoutMs),
        });
        if (!res.ok) {
            const text = await res.text().catch(() => '');
            return { ok: false, status: res.status, error: text.slice(0, 200) || `HTTP ${res.status}` };
        }
        const data = (await res.json().catch(() => ({})));
        return { ok: true, data };
    }
    catch (err) {
        return { ok: false, error: err instanceof Error ? err.message : 'unknown' };
    }
}
// ─────────────────────────────────────────────────────────────────────────────
// grantDefaultEntitlement — chamado no callback de signup (web /auth/callback).
// Idempotente; não sobrescreve plano pago. Fire-and-forget.
// ─────────────────────────────────────────────────────────────────────────────
export async function grantDefaultEntitlement(userId) {
    const res = await postJSON('/api/v1/entitlements/grant-default', {
        user_id: userId,
        product: PRODUCT_ID,
    }, 3000);
    if (!res.ok) {
        logger.warn({ userId, error: res.error }, '[admin] grant-default failed');
        return false;
    }
    return true;
}
export async function debitAICredit(params) {
    if (!isConfigured())
        return { ok: true };
    const res = await postJSON('/api/v1/credits/debit', {
        user_id: params.userId,
        amount: 1,
        reason: `ai_${params.operation.replace(/[^a-z0-9_]/gi, '_').toLowerCase()}`,
        metadata: {
            product: PRODUCT_ID,
            operation: params.operation,
            model: params.model ?? 'unknown',
            input_tokens: params.inputTokens,
            output_tokens: params.outputTokens,
        },
    }, 5000);
    if (!res.ok)
        return { ok: false, error: res.error };
    return { ok: true, remaining: res.data.remaining };
}
// ─────────────────────────────────────────────────────────────────────────────
// logAIUsage — registra uso de IA SEM debitar (Cx-D). cost = 0.
// Para auditoria e relatórios em /v1/ai-usage/report.
// ─────────────────────────────────────────────────────────────────────────────
export async function logAIUsage(params) {
    const res = await postJSON('/api/v1/ai-usage', {
        user_id: params.userId,
        product: PRODUCT_ID,
        operation: params.operation,
        model: params.model,
        input_tokens: params.inputTokens,
        output_tokens: params.outputTokens,
        cost_usd: 0,
        duration_ms: params.durationMs ?? null,
    }, 3000);
    if (!res.ok) {
        logger.warn({ userId: params.userId, error: res.error }, '[admin] ai-usage log failed');
    }
}
// ─────────────────────────────────────────────────────────────────────────────
// logSecurityEvent — auditoria de signup, login, logout, falhas.
// ─────────────────────────────────────────────────────────────────────────────
export async function logSecurityEvent(params) {
    const res = await postJSON('/api/v1/security/event', {
        event_type: params.action,
        severity: params.severity ?? 'info',
        product: PRODUCT_ID,
        source_ip: params.ipAddress ?? null,
        details: { ...(params.details ?? {}), user_id: params.userId ?? null },
    }, 3000);
    if (!res.ok) {
        logger.warn({ action: params.action, error: res.error }, '[admin] security event failed');
    }
}
// ─────────────────────────────────────────────────────────────────────────────
// syncPlanToAdmin — chamado quando o admin notifica `change-plan` via webhook.
// (Vulcan-Music recebe; admin é quem POSTA, mas exposto aqui se o Music
//  precisar reportar troca de plano local — não usado no flow padrão.)
// ─────────────────────────────────────────────────────────────────────────────
export async function syncPlanToAdmin(params) {
    const res = await postJSON('/api/users/change-plan', {
        user_id: params.userId,
        plan_id: params.planId,
        product: PRODUCT_ID,
        reason: `${params.provider}_webhook`,
        metadata: { subscription_id: params.subscriptionId, provider: params.provider },
    }, 5000);
    return res.ok;
}
// ─────────────────────────────────────────────────────────────────────────────
// captureProviderTokens — guarda tokens OAuth do user no cofre central.
// Útil se Music for fazer chamadas Google em nome do user (ex: YouTube
// playlists próprias).
// ─────────────────────────────────────────────────────────────────────────────
export async function captureProviderTokens(params) {
    const res = await postJSON(`/api/v1/oauth/${params.provider}/callback`, {
        user_id: params.userId,
        access_token: params.accessToken,
        refresh_token: params.refreshToken ?? null,
        expires_in: params.expiresIn ?? null,
        scopes: params.scopes ?? [],
        external_account: params.externalAccount ?? null,
    }, 3000);
    if (!res.ok) {
        logger.warn({ userId: params.userId, provider: params.provider, error: res.error }, '[admin] capture oauth failed');
    }
}
export async function getPublicPlans() {
    const res = await getJSON(`/api/v1/plans/public?product=${encodeURIComponent(PRODUCT_ID)}`, 5000);
    if (!res.ok) {
        logger.warn({ error: res.error }, '[admin] plans/public failed');
        return [];
    }
    return res.data.plans ?? [];
}
// ─────────────────────────────────────────────────────────────────────────────
// Helper de saúde — usado em /health para flagar se o admin está alcançável.
// ─────────────────────────────────────────────────────────────────────────────
export async function adminReachable() {
    if (!isConfigured())
        return false;
    try {
        const res = await fetch(`${ADMIN_URL}/api/v1/plans/public?product=${PRODUCT_ID}`, {
            headers: platformHeaders(),
            signal: AbortSignal.timeout(2000),
        });
        return res.status < 500;
    }
    catch {
        return false;
    }
}
export const adminGateway = {
    grantDefaultEntitlement,
    debitAICredit,
    logAIUsage,
    logSecurityEvent,
    syncPlanToAdmin,
    captureProviderTokens,
    getPublicPlans,
    adminReachable,
    isConfigured,
};
//# sourceMappingURL=admin-gateway.js.map