"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SalesforceAgentforceProvider = void 0;
const node_crypto_1 = require("node:crypto");
const cache_1 = require("../../cache");
const logger_1 = __importDefault(require("../../logger"));
const shared_1 = require("../shared");
function normalizeDomainOrigin(raw) {
    let s = raw.trim();
    if (!s) {
        throw new Error('Salesforce Agentforce: domain URL is required');
    }
    if (!/^https?:\/\//i.test(s)) {
        s = `https://${s}`;
    }
    const url = new URL(s);
    return `${url.protocol}//${url.host}`;
}
function defaultApiInstanceBase(token) {
    const fromToken = token.api_instance_url?.trim();
    if (fromToken) {
        return fromToken.replace(/\/$/, '');
    }
    return 'https://api.salesforce.com';
}
async function postFormToken(tokenUrl, consumerKey, consumerSecret) {
    const body = new URLSearchParams({
        grant_type: 'client_credentials',
        client_id: consumerKey.trim(),
        client_secret: consumerSecret.trim(),
    });
    const res = await (0, cache_1.fetchWithCache)(tokenUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: body.toString(),
    }, shared_1.REQUEST_TIMEOUT_MS, 'json', false, 0);
    if (res.status >= 400) {
        throw new Error(`Salesforce OAuth token HTTP ${res.status}: ${JSON.stringify(res.data)}`);
    }
    const access_token = res.data?.access_token;
    if (typeof access_token !== 'string') {
        throw new Error(`Salesforce OAuth: missing access_token in response: ${JSON.stringify(res.data)}`);
    }
    return {
        access_token,
        api_instance_url: typeof res.data.api_instance_url === 'string' ? res.data.api_instance_url : undefined,
        instance_url: typeof res.data.instance_url === 'string' ? res.data.instance_url : undefined,
    };
}
function extractAgentTextFromMessagesPayload(data) {
    if (data == null) {
        return '';
    }
    if (typeof data === 'string') {
        return data;
    }
    if (typeof data !== 'object') {
        return String(data);
    }
    const root = data;
    const messages = root.messages;
    if (!Array.isArray(messages) || messages.length === 0) {
        try {
            return JSON.stringify(data);
        }
        catch {
            return '';
        }
    }
    const texts = [];
    for (const m of messages) {
        if (!m || typeof m !== 'object') {
            continue;
        }
        const msg = m;
        const type = typeof msg.type === 'string' ? msg.type : '';
        const text = typeof msg.message === 'string' ? msg.message.trim() : '';
        if (!text) {
            continue;
        }
        if (type === 'Inform' && texts.length === 0) {
            continue;
        }
        texts.push(text);
    }
    if (texts.length > 0) {
        return texts.join('\n\n').trim();
    }
    const last = messages[messages.length - 1];
    const fallback = typeof last.message === 'string' ? last.message : '';
    return fallback.trim() || JSON.stringify(messages);
}
class SalesforceAgentforceProvider {
    constructor(config, options = {}) {
        this.config = options.config ?? {};
        if (!config.consumerKey?.trim() || !config.consumerSecret?.trim()) {
            throw new Error('Salesforce Agentforce: consumer key and consumer secret are required');
        }
        if (!config.agentId?.trim()) {
            throw new Error('Salesforce Agentforce: agent ID is required');
        }
        this.consumerKey = config.consumerKey.trim();
        this.consumerSecret = config.consumerSecret.trim();
        this.domainOrigin = normalizeDomainOrigin(config.domainUrl ?? '');
        this.tokenUrl = `${this.domainOrigin}/services/oauth2/token`;
        this.agentId = config.agentId.trim();
    }
    id() {
        return `salesforce-agentforce:${this.domainOrigin}:${this.agentId}`;
    }
    async endSession(apiBase, accessToken, sessionId, endHref) {
        const url = endHref?.trim() ||
            `${apiBase}/einstein/ai-agent/v1/sessions/${encodeURIComponent(sessionId)}`;
        try {
            await (0, cache_1.fetchWithCache)(url, {
                method: 'DELETE',
                headers: { Authorization: `Bearer ${accessToken}` },
            }, shared_1.REQUEST_TIMEOUT_MS, 'text', false, 0);
        }
        catch (e) {
            logger_1.default.debug(`[Salesforce Agentforce]: session end skipped: ${String(e)}`);
        }
    }
    async callApi(prompt, _context) {
        const externalSessionKey = (0, node_crypto_1.randomUUID)();
        let sessionId;
        let endHref;
        let apiBase = 'https://api.salesforce.com';
        let accessToken;
        try {
            const token = await postFormToken(this.tokenUrl, this.consumerKey, this.consumerSecret);
            apiBase = defaultApiInstanceBase(token);
            const bearer = token.access_token;
            accessToken = bearer;
            const sessionsUrl = `${apiBase}/einstein/ai-agent/v1/agents/${encodeURIComponent(this.agentId)}/sessions`;
            const sessionBody = {
                externalSessionKey,
                instanceConfig: {
                    endpoint: this.domainOrigin,
                },
                streamingCapabilities: {
                    chunkTypes: ['Text'],
                },
                bypassUser: false,
            };
            logger_1.default.debug(`[Salesforce Agentforce]: POST session ${sessionsUrl}`);
            const sessionRes = await (0, cache_1.fetchWithCache)(sessionsUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    Authorization: `Bearer ${bearer}`,
                },
                body: JSON.stringify(sessionBody),
            }, shared_1.REQUEST_TIMEOUT_MS, 'json', false, 0);
            if (sessionRes.status >= 400) {
                return {
                    error: `Salesforce Agent session HTTP ${sessionRes.status}: ${JSON.stringify(sessionRes.data)}`,
                    metadata: { externalSessionKey },
                };
            }
            sessionId =
                typeof sessionRes.data?.sessionId === 'string' ? sessionRes.data.sessionId : undefined;
            if (!sessionId) {
                return {
                    error: `Salesforce Agent session: missing sessionId in response: ${JSON.stringify(sessionRes.data)}`,
                    metadata: { externalSessionKey },
                };
            }
            endHref = sessionRes.data?._links?.end?.href;
            const messagesUrl = `${apiBase}/einstein/ai-agent/v1/sessions/${encodeURIComponent(sessionId)}/messages`;
            const messageBody = {
                message: {
                    sequenceId: '1',
                    type: 'Text',
                    text: prompt,
                },
            };
            logger_1.default.debug(`[Salesforce Agentforce]: POST message ${messagesUrl}`);
            const msgRes = await (0, cache_1.fetchWithCache)(messagesUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    Authorization: `Bearer ${bearer}`,
                },
                body: JSON.stringify(messageBody),
            }, shared_1.REQUEST_TIMEOUT_MS, 'json', false, 0);
            if (msgRes.status >= 400) {
                await this.endSession(apiBase, bearer, sessionId, endHref);
                return {
                    error: `Salesforce Agent message HTTP ${msgRes.status}: ${JSON.stringify(msgRes.data)}`,
                    metadata: { sessionId, externalSessionKey },
                };
            }
            const output = extractAgentTextFromMessagesPayload(msgRes.data);
            await this.endSession(apiBase, bearer, sessionId, endHref);
            return {
                output,
                metadata: {
                    sessionId,
                    externalSessionKey,
                },
            };
        }
        catch (err) {
            logger_1.default.error(`[Salesforce Agentforce]: ${String(err)}`);
            if (sessionId && accessToken) {
                await this.endSession(apiBase, accessToken, sessionId, endHref);
            }
            return {
                error: `Salesforce Agentforce error: ${err instanceof Error ? err.message : String(err)}`,
                metadata: { externalSessionKey, sessionId },
            };
        }
    }
}
exports.SalesforceAgentforceProvider = SalesforceAgentforceProvider;
//# sourceMappingURL=salesforce-agentforce.js.map