"use strict";
/* ---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtHostAuthentication = void 0;
exports.createAuthenticationApiFactory = createAuthenticationApiFactory;
const ide_core_common_1 = require("@opensumi/ide-core-common");
const vscode_1 = require("../../../common/vscode");
const extension_1 = require("../../../common/vscode/extension");
function createAuthenticationApiFactory(extension, extHostAuthentication) {
    const authentication = {
        getSession(providerId, scopes, options) {
            return extHostAuthentication.getSession(extension, providerId, scopes, options);
        },
        get onDidChangeSessions() {
            return extHostAuthentication.onDidChangeSessions;
        },
        registerAuthenticationProvider(id, label, provider, options) {
            return extHostAuthentication.registerAuthenticationProvider(id, label, provider, options);
        },
        get onDidChangeAuthenticationProviders() {
            return extHostAuthentication.onDidChangeAuthenticationProviders;
        },
        get providers() {
            return extHostAuthentication.providers;
        },
        logout(providerId, sessionId) {
            return extHostAuthentication.logout(providerId, sessionId);
        },
        getAccounts(providerId) {
            return extHostAuthentication.getAccounts(providerId);
        },
    };
    return authentication;
}
// some code copied and modified from https://github.com/microsoft/vscode/blob/main/src/vs/workbench/api/common/extHostAuthentication.ts#L24
class ExtHostAuthentication {
    constructor(mainContext) {
        this.logger = (0, ide_core_common_1.getDebugLogger)();
        this._authenticationProviders = new Map();
        this._providers = [];
        this._onDidChangeAuthenticationProviders = new ide_core_common_1.Emitter();
        this.onDidChangeAuthenticationProviders = this._onDidChangeAuthenticationProviders.event;
        this._onDidChangeSessions = new ide_core_common_1.Emitter();
        this.onDidChangeSessions = this._onDidChangeSessions.event;
        this._inFlightRequests = new Map();
        this._proxy = mainContext.getProxy(vscode_1.MainThreadAPIIdentifier.MainThreadAuthentication);
    }
    $setProviders(providers) {
        this._providers = providers;
        return Promise.resolve();
    }
    getProviderIds() {
        return this._proxy.$getProviderIds();
    }
    get providers() {
        return Object.freeze(this._providers.slice());
    }
    async getSession(requestingExtension, providerId, scopes, options = {}) {
        const extensionId = extension_1.ExtensionIdentifier.toKey(requestingExtension.identifier);
        const inFlightRequests = this._inFlightRequests.get(extensionId) || [];
        const sortedScopes = scopes.sort().join(' ');
        let inFlightRequest = inFlightRequests.find((request) => request.scopes === sortedScopes);
        if (inFlightRequest) {
            return inFlightRequest.result;
        }
        else {
            const session = this._getSession(requestingExtension, extensionId, providerId, scopes, options);
            inFlightRequest = {
                scopes: sortedScopes,
                result: session,
            };
            inFlightRequests.push(inFlightRequest);
            this._inFlightRequests.set(extensionId, inFlightRequests);
            try {
                await session;
            }
            catch (e) {
                this.logger.error(`get session had a error ${e.message} `);
            }
            finally {
                const requestIndex = inFlightRequests.findIndex((request) => request.scopes === sortedScopes);
                if (requestIndex > -1) {
                    inFlightRequests.splice(requestIndex);
                    this._inFlightRequests.set(extensionId, inFlightRequests);
                }
            }
            return session;
        }
    }
    async _getSession(requestingExtension, extensionId, providerId, scopes, options = {}) {
        await this._proxy.$ensureProvider(providerId);
        const extensionName = requestingExtension.displayName || requestingExtension.name;
        return this._proxy.$getSession(providerId, scopes, extensionId, extensionName, options);
    }
    async logout(providerId, sessionId) {
        return this._proxy.$logout(providerId, sessionId);
    }
    async getAccounts(providerId) {
        return this._proxy.$getAccounts(providerId);
    }
    registerAuthenticationProvider(id, label, provider, options) {
        var _a;
        if (this._authenticationProviders.get(id)) {
            throw new Error(`An authentication provider with id '${id}' is already registered.`);
        }
        this._authenticationProviders.set(id, { label, provider, options: options !== null && options !== void 0 ? options : { supportsMultipleAccounts: false } });
        if (!this._providers.find((p) => p.id === id)) {
            this._providers.push({
                id,
                label,
            });
        }
        if (!this._providers.find((p) => p.id === id)) {
            this._providers.push({
                id,
                label,
            });
        }
        const listener = provider.onDidChangeSessions((e) => {
            var _a, _b, _c;
            this._proxy.$sendDidChangeSessions(id, {
                added: (_a = e.added) !== null && _a !== void 0 ? _a : [],
                changed: (_b = e.changed) !== null && _b !== void 0 ? _b : [],
                removed: (_c = e.removed) !== null && _c !== void 0 ? _c : [],
            });
        });
        this._proxy.$registerAuthenticationProvider(id, label, (_a = options === null || options === void 0 ? void 0 : options.supportsMultipleAccounts) !== null && _a !== void 0 ? _a : false);
        return ide_core_common_1.Disposable.create(() => {
            listener.dispose();
            this._authenticationProviders.delete(id);
            const index = this._providers.findIndex((p) => p.id === id);
            if (index > -1) {
                this._providers.splice(index);
            }
            this._proxy.$unregisterAuthenticationProvider(id);
        });
    }
    $login(providerId, scopes, options) {
        const providerData = this._authenticationProviders.get(providerId);
        if (providerData) {
            return Promise.resolve(providerData.provider.createSession(scopes, options));
        }
        throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
    }
    $logout(providerId, sessionId) {
        const providerData = this._authenticationProviders.get(providerId);
        if (providerData) {
            return Promise.resolve(providerData.provider.removeSession(sessionId));
        }
        throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
    }
    $getSessions(providerId, scopes, options) {
        const providerData = this._authenticationProviders.get(providerId);
        if (providerData) {
            return Promise.resolve(providerData.provider.getSessions(scopes, options));
        }
        throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
    }
    async $getSessionAccessToken(providerId, sessionId) {
        const providerData = this._authenticationProviders.get(providerId);
        if (providerData) {
            const sessions = await providerData.provider.getSessions();
            const session = sessions.find((session) => session.id === sessionId);
            if (session) {
                return session.accessToken;
            }
            throw new Error(`Unable to find session with id: ${sessionId}`);
        }
        throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
    }
    $onDidChangeAuthenticationSessions(id, label, event) {
        this._onDidChangeSessions.fire({ provider: { id, label }, ...event });
        return Promise.resolve();
    }
    $onDidChangeAuthenticationProviders(added, removed) {
        added.forEach((provider) => {
            if (!this._providers.some((p) => p.id === provider.id)) {
                this._providers.push(provider);
            }
        });
        removed.forEach((p) => {
            const index = this._providers.findIndex((provider) => provider.id === p.id);
            if (index > -1) {
                this._providers.splice(index);
            }
        });
        this._onDidChangeAuthenticationProviders.fire({ added, removed });
        return Promise.resolve();
    }
}
exports.ExtHostAuthentication = ExtHostAuthentication;
//# sourceMappingURL=ext.host.authentication.js.map