import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { Emitter, Event } from '../../../../base/common/event.js';
import { Disposable, DisposableMap, isDisposable, DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js';
import { isFalsyOrWhitespace } from '../../../../base/common/strings.js';
import { isString } from '../../../../base/common/types.js';
import { localizeWithPath } from '../../../../nls.js';
import '../../../../platform/instantiation/common/extensions.js';
import { IAuthenticationAccessService } from './authenticationAccessService.service.js';
import '../../../../platform/instantiation/common/instantiation.js';
import { IBrowserWorkbenchEnvironmentService } from '../../environment/browser/environmentService.service.js';
import { ActivationKind } from '../../extensions/common/extensions.js';
import { IExtensionService } from '../../extensions/common/extensions.service.js';
const _moduleId = "vs/workbench/services/authentication/browser/authenticationService";
function getAuthenticationProviderActivationEvent(id) { return `onAuthenticationRequest:${id}`; }
async function getCurrentAuthenticationSessionInfo(secretStorageService, productService) {
    const authenticationSessionValue = await secretStorageService.get(`${productService.urlProtocol}.loginAccount`);
    if (authenticationSessionValue) {
        try {
            const authenticationSessionInfo = JSON.parse(authenticationSessionValue);
            if (authenticationSessionInfo
                && isString(authenticationSessionInfo.id)
                && isString(authenticationSessionInfo.accessToken)
                && isString(authenticationSessionInfo.providerId)) {
                return authenticationSessionInfo;
            }
        }
        catch (e) {
            console.error(`Failed parsing current auth session value: ${e}`);
        }
    }
    return undefined;
}
let AuthenticationService = class AuthenticationService extends Disposable {
    constructor(_extensionService, authenticationAccessService, _environmentService) {
        super();
        this._extensionService = _extensionService;
        this._environmentService = _environmentService;
        this._onDidRegisterAuthenticationProvider = this._register(( new Emitter()));
        this.onDidRegisterAuthenticationProvider = this._onDidRegisterAuthenticationProvider.event;
        this._onDidUnregisterAuthenticationProvider = this._register(( new Emitter()));
        this.onDidUnregisterAuthenticationProvider = this._onDidUnregisterAuthenticationProvider.event;
        this._onDidChangeSessions = this._register(( new Emitter()));
        this.onDidChangeSessions = this._onDidChangeSessions.event;
        this._onDidChangeDeclaredProviders = this._register(( new Emitter()));
        this.onDidChangeDeclaredProviders = this._onDidChangeDeclaredProviders.event;
        this._authenticationProviders = ( new Map());
        this._authenticationProviderDisposables = this._register(( new DisposableMap()));
        this._declaredProviders = [];
        this._register(authenticationAccessService.onDidChangeExtensionSessionAccess(e => {
            this._onDidChangeSessions.fire({
                providerId: e.providerId,
                label: e.accountName,
                event: {
                    added: [],
                    changed: [],
                    removed: []
                }
            });
        }));
        this._registerEnvContributedAuthenticationProviders();
    }
    get declaredProviders() {
        return this._declaredProviders;
    }
    _registerEnvContributedAuthenticationProviders() {
        if (!this._environmentService.options?.authenticationProviders?.length) {
            return;
        }
        for (const provider of this._environmentService.options.authenticationProviders) {
            this.registerAuthenticationProvider(provider.id, provider);
        }
    }
    registerDeclaredAuthenticationProvider(provider) {
        if (isFalsyOrWhitespace(provider.id)) {
            throw ( new Error(
                localizeWithPath(_moduleId, 0, 'An authentication contribution must specify an id.')
            ));
        }
        if (isFalsyOrWhitespace(provider.label)) {
            throw ( new Error(
                localizeWithPath(_moduleId, 1, 'An authentication contribution must specify a label.')
            ));
        }
        if (( this.declaredProviders.some(p => p.id === provider.id))) {
            throw ( new Error(localizeWithPath(
                _moduleId,
                2,
                "This authentication id '{0}' has already been registered",
                provider.id
            )));
        }
        this._declaredProviders.push(provider);
        this._onDidChangeDeclaredProviders.fire();
    }
    unregisterDeclaredAuthenticationProvider(id) {
        const index = this.declaredProviders.findIndex(provider => provider.id === id);
        if (index > -1) {
            this.declaredProviders.splice(index, 1);
        }
        this._onDidChangeDeclaredProviders.fire();
    }
    isAuthenticationProviderRegistered(id) {
        return ( this._authenticationProviders.has(id));
    }
    registerAuthenticationProvider(id, authenticationProvider) {
        this._authenticationProviders.set(id, authenticationProvider);
        const disposableStore = ( new DisposableStore());
        disposableStore.add(authenticationProvider.onDidChangeSessions(e => this._onDidChangeSessions.fire({
            providerId: id,
            label: authenticationProvider.label,
            event: e
        })));
        if (isDisposable(authenticationProvider)) {
            disposableStore.add(authenticationProvider);
        }
        this._authenticationProviderDisposables.set(id, disposableStore);
        this._onDidRegisterAuthenticationProvider.fire({ id, label: authenticationProvider.label });
    }
    unregisterAuthenticationProvider(id) {
        const provider = this._authenticationProviders.get(id);
        if (provider) {
            this._authenticationProviders.delete(id);
            this._onDidUnregisterAuthenticationProvider.fire({ id, label: provider.label });
        }
        this._authenticationProviderDisposables.deleteAndDispose(id);
    }
    getProviderIds() {
        const providerIds = [];
        this._authenticationProviders.forEach(provider => {
            providerIds.push(provider.id);
        });
        return providerIds;
    }
    getProvider(id) {
        if (( this._authenticationProviders.has(id))) {
            return this._authenticationProviders.get(id);
        }
        throw ( new Error(`No authentication provider '${id}' is currently registered.`));
    }
    async getSessions(id, scopes, account, activateImmediate = false) {
        const authProvider = this._authenticationProviders.get(id) || (await this.tryActivateProvider(id, activateImmediate));
        if (authProvider) {
            return await authProvider.getSessions(scopes, { account });
        }
        else {
            throw ( new Error(`No authentication provider '${id}' is currently registered.`));
        }
    }
    async createSession(id, scopes, options) {
        const authProvider = this._authenticationProviders.get(id) || (await this.tryActivateProvider(id, !!options?.activateImmediate));
        if (authProvider) {
            return await authProvider.createSession(scopes, {
                account: options?.account
            });
        }
        else {
            throw ( new Error(`No authentication provider '${id}' is currently registered.`));
        }
    }
    async removeSession(id, sessionId) {
        const authProvider = this._authenticationProviders.get(id);
        if (authProvider) {
            return authProvider.removeSession(sessionId);
        }
        else {
            throw ( new Error(`No authentication provider '${id}' is currently registered.`));
        }
    }
    async tryActivateProvider(providerId, activateImmediate) {
        await this._extensionService.activateByEvent(getAuthenticationProviderActivationEvent(providerId), activateImmediate ? ActivationKind.Immediate : ActivationKind.Normal);
        let provider = this._authenticationProviders.get(providerId);
        if (provider) {
            return provider;
        }
        const store = ( new DisposableStore());
        const didRegister = ( new Promise((resolve, _) => {
            store.add(Event.once(this.onDidRegisterAuthenticationProvider)(e => {
                if (e.id === providerId) {
                    provider = this._authenticationProviders.get(providerId);
                    if (provider) {
                        resolve(provider);
                    }
                    else {
                        throw ( new Error(`No authentication provider '${providerId}' is currently registered.`));
                    }
                }
            }));
        }));
        const didTimeout = ( new Promise((_, reject) => {
            const handle = setTimeout(() => {
                reject('Timed out waiting for authentication provider to register');
            }, 5000);
            store.add(toDisposable(() => clearTimeout(handle)));
        }));
        return Promise.race([didRegister, didTimeout]).finally(() => store.dispose());
    }
};
AuthenticationService = ( __decorate([
    ( __param(0, IExtensionService)),
    ( __param(1, IAuthenticationAccessService)),
    ( __param(2, IBrowserWorkbenchEnvironmentService))
], AuthenticationService));
export { AuthenticationService, getAuthenticationProviderActivationEvent, getCurrentAuthenticationSessionInfo };
