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());
    });
};
/**
 * @private
 */
export class ResourceDownloadQueue {
    constructor(context, authentication) {
        this._messagesNeedingResourceRetrieval = [];
        this.isActive = false;
        this._requestsToCancel = {};
        this._context = context;
        this._credential = authentication.credential;
        this._endpoint = authentication.endpoint;
    }
    containsMessageWithSameAttachments(message) {
        var _a, _b, _c;
        let contains = false;
        const incomingAttachment = (_a = message.content) === null || _a === void 0 ? void 0 : _a.attachments;
        if (incomingAttachment) {
            for (const m of this._messagesNeedingResourceRetrieval) {
                const existingAttachment = (_c = (_b = m.content) === null || _b === void 0 ? void 0 : _b.attachments) !== null && _c !== void 0 ? _c : [];
                contains = incomingAttachment.every((element, index) => element === existingAttachment[index]);
                if (contains) {
                    break;
                }
            }
        }
        return contains;
    }
    addMessage(message) {
        // make a copy of message and add to queue
        const copy = Object.assign({}, message);
        this._messagesNeedingResourceRetrieval.push(copy);
    }
    startQueue(threadId, operation, options) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.isActive) {
                return;
            }
            while (this._messagesNeedingResourceRetrieval.length > 0) {
                this.isActive = true;
                let message = this._messagesNeedingResourceRetrieval.shift();
                if (!message) {
                    this.isActive = false;
                    continue;
                }
                if (options) {
                    const singleUrl = options.singleUrl;
                    message = yield this.downloadSingleUrl(message, singleUrl, operation);
                }
                else {
                    message = yield this.downloadAllPreviewUrls(message, operation);
                }
                this._context.setChatMessage(threadId, message);
                this.isActive = false;
            }
        });
    }
    cancelAllRequests() {
        for (const cancelation of Object.values(this._requestsToCancel)) {
            cancelation.abortController.abort();
        }
        this._requestsToCancel = {};
    }
    cancelRequest(url) {
        var _a;
        if (this._requestsToCancel[url]) {
            (_a = this._requestsToCancel[url]) === null || _a === void 0 ? void 0 : _a.abortController.abort();
            delete this._requestsToCancel[url];
        }
    }
    downloadSingleUrl(message, resourceUrl, operation) {
        return __awaiter(this, void 0, void 0, function* () {
            const response = {
                sourceUrl: ''
            };
            try {
                const abortController = new AbortController();
                const blobUrl = yield this.downloadResource(operation, resourceUrl, abortController);
                response.sourceUrl = blobUrl;
            }
            catch (error) {
                response.error = error;
                delete this._requestsToCancel[resourceUrl];
            }
            message = Object.assign(Object.assign({}, message), { resourceCache: Object.assign(Object.assign({}, message.resourceCache), { [resourceUrl]: response }) });
            return message;
        });
    }
    downloadAllPreviewUrls(message, operation) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const attachments = (_a = message.content) === null || _a === void 0 ? void 0 : _a.attachments;
            if (message.type === 'html' && attachments) {
                if (message.resourceCache === undefined) {
                    message.resourceCache = {};
                }
                for (const attachment of attachments) {
                    if (attachment.previewUrl && attachment.attachmentType === 'image') {
                        const response = {
                            sourceUrl: ''
                        };
                        try {
                            const abortController = new AbortController();
                            const blobUrl = yield this.downloadResource(operation, attachment.previewUrl, abortController);
                            response.sourceUrl = blobUrl;
                        }
                        catch (error) {
                            response.error = error;
                            delete this._requestsToCancel[attachment.previewUrl];
                        }
                        message.resourceCache[attachment.previewUrl] = response;
                    }
                }
            }
            return message;
        });
    }
    downloadResource(operation, url, abortController) {
        return __awaiter(this, void 0, void 0, function* () {
            this._requestsToCancel[url] = {
                src: url,
                abortController
            };
            const blobUrl = yield operation(url, {
                credential: this._credential,
                endpoint: this._endpoint
            }, {
                abortController
            });
            delete this._requestsToCancel[url];
            return blobUrl;
        });
    }
}
/**
 * @private
 */
export const fetchImageSource = (src, authentication, options) => __awaiter(void 0, void 0, void 0, function* () {
    function fetchWithAuthentication(url, token, options) {
        return __awaiter(this, void 0, void 0, function* () {
            const headers = new Headers();
            headers.append('Authorization', `Bearer ${token}`);
            return yield fetchWithTimeout(url, {
                timeout: options.timeout,
                headers,
                abortController: options.abortController
            });
        });
    }
    function fetchWithTimeout(resource, options) {
        return __awaiter(this, void 0, void 0, function* () {
            // default timeout is 30 seconds
            const { timeout = 30000, abortController } = options;
            const id = setTimeout(() => {
                abortController.abort();
            }, timeout);
            const response = yield fetch(resource, Object.assign(Object.assign({}, options), { signal: abortController.signal }));
            clearTimeout(id);
            return response;
        });
    }
    const fetchUrl = new URL(src);
    const endpoint = new URL(authentication.endpoint);
    let token = '';
    if (fetchUrl.hostname === endpoint.hostname && fetchUrl.protocol === 'https:') {
        token = (yield authentication.credential.getToken()).token;
    }
    const response = yield fetchWithAuthentication(src, token, options);
    if (response.status >= 400) {
        throw new Error(`Failed to fetch image source. Status code: ${response.status}`);
    }
    const blob = yield response.blob();
    return URL.createObjectURL(blob);
});
//# sourceMappingURL=ResourceDownloadQueue.js.map