
import { __decorate, __param } from '../../../../../../external/tslib/tslib.es6.js';
import { Emitter, Event } from '../../../base/common/event.js';
import { MainContext } from './extHost.protocol.js';
import { Disposable } from './extHostTypes.js';
import { ExtensionIdentifier } from '../../../platform/extensions/common/extensions.js';
import { INTERNAL_AUTH_PROVIDER_PREFIX } from '../../services/authentication/common/authentication.js';
import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
import { IExtHostRpcService } from './extHostRpcService.js';

const IExtHostAuthentication = ( createDecorator('IExtHostAuthentication'));
let ExtHostAuthentication = class ExtHostAuthentication {
    constructor(extHostRpc) {
        this._authenticationProviders = ( new Map());
        this._onDidChangeSessions = ( new Emitter());
        this._getSessionTaskSingler = ( new TaskSingler());
        this._proxy = ( extHostRpc.getProxy(MainContext.MainThreadAuthentication));
    }
    getExtensionScopedSessionsEvent(extensionId) {
        const normalizedExtensionId = extensionId.toLowerCase();
        return Event.chain(this._onDidChangeSessions.event, ($) => ( $
            .filter(e => !e.extensionIdFilter || e.extensionIdFilter.includes(normalizedExtensionId))
            .map(e => ({ provider: e.provider }))));
    }
    async getSession(requestingExtension, providerId, scopes, options = {}) {
        const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier);
        const sortedScopes = [...scopes].sort().join(' ');
        const keys = ( Object.keys(options));
        const optionsStr = ( keys.sort().map(key => `${key}:${!!options[key]}`)).join(', ');
        return await this._getSessionTaskSingler.getOrCreate(`${extensionId} ${providerId} ${sortedScopes} ${optionsStr}`, async () => {
            await this._proxy.$ensureProvider(providerId);
            const extensionName = requestingExtension.displayName || requestingExtension.name;
            return this._proxy.$getSession(providerId, scopes, extensionId, extensionName, options);
        });
    }
    async getAccounts(providerId) {
        await this._proxy.$ensureProvider(providerId);
        return await this._proxy.$getAccounts(providerId);
    }
    async removeSession(providerId, sessionId) {
        const providerData = this._authenticationProviders.get(providerId);
        if (!providerData) {
            return this._proxy.$removeSession(providerId, sessionId);
        }
        return providerData.provider.removeSession(sessionId);
    }
    registerAuthenticationProvider(id, label, provider, options) {
        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 ?? { supportsMultipleAccounts: false } });
        const listener = provider.onDidChangeSessions(e => this._proxy.$sendDidChangeSessions(id, e));
        this._proxy.$registerAuthenticationProvider(id, label, options?.supportsMultipleAccounts ?? false);
        return ( new Disposable(() => {
            listener.dispose();
            this._authenticationProviders.delete(id);
            this._proxy.$unregisterAuthenticationProvider(id);
        }));
    }
    async $createSession(providerId, scopes, options) {
        const providerData = this._authenticationProviders.get(providerId);
        if (providerData) {
            return await providerData.provider.createSession(scopes, options);
        }
        throw ( new Error(`Unable to find authentication provider with handle: ${providerId}`));
    }
    async $removeSession(providerId, sessionId) {
        const providerData = this._authenticationProviders.get(providerId);
        if (providerData) {
            return await providerData.provider.removeSession(sessionId);
        }
        throw ( new Error(`Unable to find authentication provider with handle: ${providerId}`));
    }
    async $getSessions(providerId, scopes, options) {
        const providerData = this._authenticationProviders.get(providerId);
        if (providerData) {
            return await providerData.provider.getSessions(scopes, options);
        }
        throw ( new Error(`Unable to find authentication provider with handle: ${providerId}`));
    }
    $onDidChangeAuthenticationSessions(id, label, extensionIdFilter) {
        if (!id.startsWith(INTERNAL_AUTH_PROVIDER_PREFIX)) {
            this._onDidChangeSessions.fire({ provider: { id, label }, extensionIdFilter });
        }
        return Promise.resolve();
    }
};
ExtHostAuthentication = ( __decorate([
    ( __param(0, IExtHostRpcService))
], ExtHostAuthentication));
class TaskSingler {
    constructor() {
        this._inFlightPromises = ( new Map());
    }
    getOrCreate(key, promiseFactory) {
        const inFlight = this._inFlightPromises.get(key);
        if (inFlight) {
            return inFlight;
        }
        const promise = promiseFactory().finally(() => this._inFlightPromises.delete(key));
        this._inFlightPromises.set(key, promise);
        return promise;
    }
}

export { ExtHostAuthentication, IExtHostAuthentication };
