/**
 * ╔══════════════════════════════════════════════════════════════════════╗
 * ║   OVERMIND BRIDGE — WebhookAdapter (Generic Webhook → Bridge)        ║
 * ║                                                                      ║
 * ║   Normalise les webhooks de providers variés vers un format         ║
 * ║   uniforme consommable par l'API agent.run.                         ║
 * ║                                                                      ║
 * ║   PROVIDERS SUPPORTÉS                                                ║
 * ║   ────────────────────                                               ║
 * ║   - voipms    : VoIP.ms (from, to, message, id, date, media)        ║
 * ║   - twilio    : Twilio (From, To, Body, MessageSid, MediaUrl0)       ║
 * ║   - generic   : Format customisable (mapping field-by-field)         ║
 * ║                                                                      ║
 * ║   Chaque adapter retourne un NormalizedWebhook qui contient :        ║
 * ║     - externalKey : clé pour SessionStore (phone, user, etc.)       ║
 * ║     - prompt      : texte à envoyer à l'agent (déjà contextualisé)  ║
 * ║     - metadata    : données brutes pour audit                        ║
 * ║     - mediaUrls   : URLs de médias attachés                          ║
 * ╚══════════════════════════════════════════════════════════════════════╝
 */
import { createBridgeLogger } from './utils.js';
import { formatDiscordContext } from './utils.js';
// ─── WebhookAdapter ────────────────────────────────────────────────────────
export class WebhookAdapter {
    config;
    log;
    constructor(config = {}) {
        this.config = {
            provider: config.provider ?? 'voipms',
            promptPrefix: config.promptPrefix ?? '',
            fieldMap: config.fieldMap,
            discordContext: config.discordContext,
        };
        this.log = config.logger ?? createBridgeLogger('webhook-adapter');
    }
    /**
     * Adapte un payload brut vers un NormalizedWebhook.
     */
    adapt(rawPayload) {
        switch (this.config.provider) {
            case 'voipms':
                return this.adaptVoipMs(rawPayload);
            case 'twilio':
                return this.adaptTwilio(rawPayload);
            case 'discord':
                return this.adaptDiscord(rawPayload);
            case 'generic':
                return this.adaptGeneric(rawPayload);
            default: {
                const _exhaustive = this.config.provider;
                throw new Error(`Unknown provider: ${String(_exhaustive)}`);
            }
        }
    }
    // ─── Provider Adapters ──────────────────────────────────────────────────
    /**
     * VoIP.ms callback format.
     * Params: from, to, message, id, date, media (URLs séparées par |)
     * Body peut être GET query ou POST form-encoded.
     */
    adaptVoipMs(raw) {
        const from = stringOr(raw.from ?? raw.From, 'unknown');
        const to = stringOr(raw.to ?? raw.To, 'unknown');
        const message = stringOr(raw.message ?? raw.Message ?? raw.Body ?? raw.body, '');
        const messageId = stringOr(raw.id ?? raw.MessageSid, '');
        const date = stringOr(raw.date ?? raw.Date, new Date().toISOString());
        const mediaRaw = stringOr(raw.media ?? raw.MediaUrl0 ?? '', '');
        const mediaUrls = mediaRaw ? mediaRaw.split('|').map((u) => u.trim()).filter(Boolean) : [];
        const promptParts = [];
        if (this.config.promptPrefix)
            promptParts.push(this.config.promptPrefix);
        promptParts.push(`[Webhook VoIP.ms]`);
        promptParts.push(`From: ${from}`);
        promptParts.push(`To: ${to}`);
        promptParts.push(`Date: ${date}`);
        if (messageId)
            promptParts.push(`MessageId: ${messageId}`);
        promptParts.push('---');
        promptParts.push(message);
        if (mediaUrls.length > 0) {
            promptParts.push('---');
            promptParts.push(`Médias (${mediaUrls.length}):`);
            for (const url of mediaUrls)
                promptParts.push(`- ${url}`);
        }
        return {
            externalKey: from,
            prompt: promptParts.join('\n'),
            mediaUrls,
            metadata: { provider: 'voipms', from, to, messageId, date },
        };
    }
    /**
     * Twilio format (snake_case ou CamelCase).
     */
    adaptTwilio(raw) {
        const from = stringOr(raw.From ?? raw.from, 'unknown');
        const to = stringOr(raw.To ?? raw.to, 'unknown');
        const body = stringOr(raw.Body ?? raw.body, '');
        const messageSid = stringOr(raw.MessageSid ?? raw.SmsSid ?? raw.messageId, '');
        const numMedia = Number(raw.NumMedia ?? 0);
        const mediaUrls = [];
        for (let i = 0; i < numMedia; i++) {
            const url = raw[`MediaUrl${i}`];
            if (typeof url === 'string' && url)
                mediaUrls.push(url);
        }
        const promptParts = [];
        if (this.config.promptPrefix)
            promptParts.push(this.config.promptPrefix);
        promptParts.push(`[Webhook Twilio]`);
        promptParts.push(`From: ${from}`);
        promptParts.push(`To: ${to}`);
        if (messageSid)
            promptParts.push(`MessageSid: ${messageSid}`);
        promptParts.push('---');
        promptParts.push(body);
        if (mediaUrls.length > 0) {
            promptParts.push('---');
            promptParts.push(`Médias (${mediaUrls.length}):`);
            for (const url of mediaUrls)
                promptParts.push(`- ${url}`);
        }
        return {
            externalKey: from,
            prompt: promptParts.join('\n'),
            mediaUrls,
            metadata: { provider: 'twilio', from, to, messageSid, numMedia },
        };
    }
    /**
     * Discord-like format (channel, user, message).
     */
    adaptDiscord(raw) {
        const author = raw.author ?? undefined;
        const channelId = stringOr(raw.channelId ?? raw.channel_id, '');
        const userId = stringOr(raw.userId ?? raw.user_id ?? author?.id, '');
        const username = stringOr(raw.username ?? author?.username, 'unknown');
        const message = stringOr(raw.content ?? raw.message ?? raw.body, '');
        const prompt = formatDiscordContext({ channelId, userId, username, message });
        return {
            externalKey: userId || channelId,
            prompt: this.config.promptPrefix
                ? `${this.config.promptPrefix}\n${prompt}`
                : prompt,
            mediaUrls: Array.isArray(raw.attachments)
                ? raw.attachments.map((a) => a.url).filter((u) => Boolean(u))
                : [],
            metadata: { provider: 'discord', channelId, userId, username },
        };
    }
    /**
     * Generic — applique le fieldMap custom.
     */
    adaptGeneric(raw) {
        const map = this.config.fieldMap ?? {};
        const get = (key) => {
            const sourceKey = map[key];
            if (!sourceKey)
                return '';
            const v = raw[sourceKey];
            return typeof v === 'string' ? v : v != null ? JSON.stringify(v) : '';
        };
        const externalKey = get('externalKey') || 'default';
        const prompt = get('prompt') || JSON.stringify(raw);
        const mediaStr = get('mediaUrls');
        const mediaUrls = mediaStr ? mediaStr.split(',').map((s) => s.trim()).filter(Boolean) : [];
        return {
            externalKey,
            prompt: this.config.promptPrefix
                ? `${this.config.promptPrefix}\n${prompt}`
                : prompt,
            mediaUrls,
            metadata: { provider: 'generic', raw },
        };
    }
}
// ─── Helpers ───────────────────────────────────────────────────────────────
function stringOr(value, defaultValue) {
    if (typeof value === 'string')
        return value;
    if (value == null)
        return defaultValue;
    return String(value);
}
//# sourceMappingURL=WebhookAdapter.js.map