"use strict";
/**
 * DatadogRetentionAdapter -- P4-RET-04 Datadog retention API (AC 14)
 *
 * Wired 2026-05-02 per Thomas Layer 0 directive (F-NEW-CRIT-31).
 *
 * Configuration:
 *   - DD_API_KEY: Datadog API key with logs_write permission
 *   - DD_APP_KEY: Datadog application key
 *   - DD_SITE: Datadog site (e.g. datadoghq.com, datadoghq.eu)
 *   - DD_RETENTION_POLICY_MAP: JSON blob mapping tenantId -> policyId
 *   - opts.baseUrl (test override): full base URL like http://127.0.0.1:18889
 *
 * Behavior:
 *   - setTenantRetention(): PUT /api/v1/logs/config/retention-policy/<policyId>
 *       { period_days: <days> }
 *   - 10s default timeout, 1 retry on 5xx or network error.
 *   - On final failure, dispatches to DLQ callback (if injected) and rethrows.
 *
 * Spec: P4-RET-01 Section 2.4, AC 14
 *
 * @connexum/ai-governance
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.DatadogRetentionAdapter = void 0;
const ADAPTER_TAG = 'datadog-retention';
const DEFAULT_TIMEOUT_MS = 10_000;
class DatadogRetentionAdapter {
    aggregatorType = 'datadog';
    apiKey;
    appKey;
    site;
    baseUrl;
    policyMap;
    timeoutMs;
    dlq;
    fetchImpl;
    constructor(opts) {
        this.apiKey = opts?.apiKey ?? process.env.DD_API_KEY;
        this.appKey = opts?.appKey ?? process.env.DD_APP_KEY;
        this.site = opts?.site ?? process.env.DD_SITE ?? 'datadoghq.com';
        this.baseUrl = opts?.baseUrl;
        const rawMap = opts?.policyMap ??
            (process.env.DD_RETENTION_POLICY_MAP
                ? JSON.parse(process.env.DD_RETENTION_POLICY_MAP)
                : {});
        this.policyMap = new Map(Object.entries(rawMap));
        this.timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
        this.dlq = opts?.dlq;
        this.fetchImpl = opts?.fetchImpl ?? globalThis.fetch;
    }
    async setTenantRetention(tenantId, days) {
        if (!this.apiKey || !this.appKey) {
            console.warn(`[${ADAPTER_TAG}] no credentials configured. Tenant=${tenantId}, days=${days}. ` +
                `Set DD_API_KEY + DD_APP_KEY to enable.`);
            return;
        }
        const policyId = this.policyMap.get(tenantId);
        if (!policyId) {
            console.warn(`[${ADAPTER_TAG}] no policyId mapped for tenant=${tenantId}. ` +
                `Update DD_RETENTION_POLICY_MAP to enable.`);
            return;
        }
        const base = this.baseUrl
            ? this.baseUrl.replace(/\/$/, '')
            : `https://api.${this.site}`;
        const url = `${base}/api/v1/logs/config/retention-policy/${encodeURIComponent(policyId)}`;
        const body = JSON.stringify({ period_days: days });
        const headers = {
            'DD-API-KEY': this.apiKey,
            'DD-APPLICATION-KEY': this.appKey,
            'Content-Type': 'application/json',
        };
        await this.dispatchWithRetry(tenantId, days, async () => {
            return this.doFetch(url, { method: 'PUT', headers, body });
        });
    }
    async getTenantRetention(tenantId) {
        if (!this.apiKey || !this.appKey)
            return null;
        const policyId = this.policyMap.get(tenantId);
        if (!policyId)
            return null;
        const base = this.baseUrl
            ? this.baseUrl.replace(/\/$/, '')
            : `https://api.${this.site}`;
        const url = `${base}/api/v1/logs/config/retention-policy/${encodeURIComponent(policyId)}`;
        try {
            const res = await this.doFetch(url, {
                method: 'GET',
                headers: { 'DD-API-KEY': this.apiKey, 'DD-APPLICATION-KEY': this.appKey },
            });
            if (!res.ok)
                return null;
            const json = (await res.json());
            return typeof json.period_days === 'number' ? json.period_days : null;
        }
        catch {
            return null;
        }
    }
    async doFetch(url, init) {
        const controller = new AbortController();
        const timer = setTimeout(() => controller.abort(), this.timeoutMs);
        try {
            return await this.fetchImpl(url, { ...init, signal: controller.signal });
        }
        finally {
            clearTimeout(timer);
        }
    }
    async dispatchWithRetry(tenantId, days, op) {
        let lastErr;
        for (let attempt = 1; attempt <= 2; attempt++) {
            try {
                const res = await op();
                if (res.ok)
                    return;
                if (res.status >= 500 && attempt === 1) {
                    lastErr = new Error(`Datadog retention API ${res.status} ${res.statusText}`);
                    continue;
                }
                throw new Error(`Datadog retention API failed: ${res.status} ${res.statusText}`);
            }
            catch (err) {
                lastErr = err;
                if (attempt === 1 && this.isRetryable(err))
                    continue;
                break;
            }
        }
        const errMsg = lastErr instanceof Error ? lastErr.message : String(lastErr);
        if (this.dlq) {
            this.dlq({
                adapterType: this.aggregatorType,
                tenantId,
                days,
                attempts: 2,
                error: errMsg,
                occurredAt: new Date().toISOString(),
            });
        }
        console.error(`[${ADAPTER_TAG}] retention push failed after retry. tenant=${tenantId} days=${days} err=${errMsg}`);
        throw lastErr instanceof Error ? lastErr : new Error(errMsg);
    }
    isRetryable(err) {
        if (!(err instanceof Error))
            return false;
        return (err.name === 'AbortError' ||
            err.message.includes('ECONNREFUSED') ||
            err.message.includes('ECONNRESET') ||
            err.message.includes('ETIMEDOUT') ||
            err.message.includes('fetch failed'));
    }
}
exports.DatadogRetentionAdapter = DatadogRetentionAdapter;
//# sourceMappingURL=datadog.js.map