"use strict";
/**
 * @module botbuilder
 */
/**
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BotFrameworkHttpClient = void 0;
const axios_1 = require("axios");
const botbuilder_core_1 = require("botbuilder-core");
const botframework_connector_1 = require("botframework-connector");
const botFrameworkAdapter_1 = require("./botFrameworkAdapter");
/**
 * HttpClient for calling skills from a Node.js BotBuilder V4 SDK bot.
 */
class BotFrameworkHttpClient {
    /**
     * Creates a new instance of the [BotFrameworkHttpClient](xref:botbuilder.BotFrameworkHttpClient) class
     * @param credentialProvider An instance of [ICredentialProvider](xref:botframework-connector.ICredentialProvider).
     * @param channelService Optional. The channel service.
     */
    constructor(credentialProvider, channelService) {
        if (!credentialProvider) {
            throw new Error('BotFrameworkHttpClient(): missing credentialProvider');
        }
        this.credentialProvider = credentialProvider;
        this.channelService = channelService || process.env[botframework_connector_1.AuthenticationConstants.ChannelService];
    }
    /**
     * Forwards an activity to another bot.
     * @remarks
     *
     * @template T The type of body in the InvokeResponse.
     * @param fromBotId The MicrosoftAppId of the bot sending the activity.
     * @param toBotId The MicrosoftAppId of the bot receiving the activity.
     * @param toUrl The URL of the bot receiving the activity.
     * @param serviceUrl The callback Url for the skill host.
     * @param conversationId A conversation ID to use for the conversation with the skill.
     * @param activity Activity to forward.
     */
    postActivity(fromBotId, toBotId, toUrl, serviceUrl, conversationId, activity) {
        return __awaiter(this, void 0, void 0, function* () {
            const appCredentials = yield this.getAppCredentials(fromBotId, toBotId);
            if (!appCredentials) {
                throw new Error('BotFrameworkHttpClient.postActivity(): Unable to get appCredentials to connect to the skill');
            }
            if (!activity) {
                throw new Error('BotFrameworkHttpClient.postActivity(): missing activity');
            }
            if (activity.conversation === undefined) {
                throw new Error('BotFrameworkHttpClient.postActivity(): Activity must have a ConversationReference');
            }
            // Get token for the skill call
            const token = appCredentials.appId ? yield appCredentials.getToken() : null;
            // Capture current activity settings before changing them.
            // TODO: DO we need to set the activity ID? (events that are created manually don't have it).
            const originalConversationId = activity.conversation.id;
            const originalServiceUrl = activity.serviceUrl;
            const originalRelatesTo = activity.relatesTo;
            const originalRecipient = activity.recipient;
            try {
                activity.relatesTo = {
                    serviceUrl: activity.serviceUrl,
                    activityId: activity.id,
                    channelId: activity.channelId,
                    conversation: {
                        id: activity.conversation.id,
                        name: activity.conversation.name,
                        conversationType: activity.conversation.conversationType,
                        aadObjectId: activity.conversation.aadObjectId,
                        isGroup: activity.conversation.isGroup,
                        properties: activity.conversation.properties,
                        role: activity.conversation.role,
                        tenantId: activity.conversation.tenantId,
                    },
                    bot: null,
                };
                activity.conversation.id = conversationId;
                activity.serviceUrl = serviceUrl;
                // Fixes: https://github.com/microsoft/botframework-sdk/issues/5785
                if (!activity.recipient) {
                    activity.recipient = {};
                }
                activity.recipient.role = botbuilder_core_1.RoleTypes.Skill;
                const config = {
                    headers: {
                        Accept: 'application/json',
                        'Content-Type': 'application/json',
                        'User-Agent': botFrameworkAdapter_1.USER_AGENT,
                    },
                    validateStatus: () => true,
                };
                if (token) {
                    config.headers.Authorization = `Bearer ${token}`;
                }
                const response = yield axios_1.default.post(toUrl, activity, config);
                return { status: response.status, body: response.data };
            }
            finally {
                // Restore activity properties.
                activity.conversation.id = originalConversationId;
                activity.serviceUrl = originalServiceUrl;
                activity.relatesTo = originalRelatesTo;
                activity.recipient = originalRecipient;
            }
        });
    }
    /**
     * Logic to build an [AppCredentials](xref:botframework-connector.AppCredentials) to be used to acquire tokens for this `HttpClient`.
     * @param appId The application id.
     * @param oAuthScope Optional. The OAuth scope.
     *
     * @returns The app credentials to be used to acquire tokens.
     */
    buildCredentials(appId, oAuthScope) {
        return __awaiter(this, void 0, void 0, function* () {
            const appPassword = yield this.credentialProvider.getAppPassword(appId);
            if (botframework_connector_1.JwtTokenValidation.isGovernment(this.channelService)) {
                const appCredentials = new botframework_connector_1.MicrosoftAppCredentials(appId, appPassword, undefined, oAuthScope);
                appCredentials.oAuthEndpoint = botframework_connector_1.GovernmentConstants.ToChannelFromBotLoginUrl;
                return appCredentials;
            }
            else {
                return new botframework_connector_1.MicrosoftAppCredentials(appId, appPassword, undefined, oAuthScope);
            }
        });
    }
    /**
     * Gets the application credentials. App Credentials are cached so as to ensure we are not refreshing
     * token every time.
     * @private
     * @param appId The application identifier (AAD Id for the bot).
     * @param oAuthScope The scope for the token, skills will use the Skill App Id.
     */
    getAppCredentials(appId, oAuthScope) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!appId) {
                return new botframework_connector_1.MicrosoftAppCredentials('', '');
            }
            const cacheKey = `${appId}${oAuthScope}`;
            let appCredentials = BotFrameworkHttpClient.appCredentialMapCache.get(cacheKey);
            if (appCredentials) {
                return appCredentials;
            }
            // Credentials not found in cache, build them
            appCredentials = yield this.buildCredentials(appId, oAuthScope);
            // Cache the credentials for later use
            BotFrameworkHttpClient.appCredentialMapCache.set(cacheKey, appCredentials);
            return appCredentials;
        });
    }
}
exports.BotFrameworkHttpClient = BotFrameworkHttpClient;
/**
 * Cache for appCredentials to speed up token acquisition (a token is not requested unless is expired)
 * AppCredentials are cached using appId + scope (this last parameter is only used if the app credentials are used to call a skill)
 */
BotFrameworkHttpClient.appCredentialMapCache = new Map();
//# sourceMappingURL=botFrameworkHttpClient.js.map