
import { Event } from '../../../../base/common/event.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import '../../../../platform/instantiation/common/instantiation.js';
import { asJson } from '../../../../platform/request/common/request.js';
import { CancellationToken } from '../../../../base/common/cancellation.js';
import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
import { registerAction2, Action2 } from '../../../../platform/actions/common/actions.js';
import { localize } from '../../../../nls.js';
import '../../../../base/common/async.js';
import { getErrorMessage } from '../../../../base/common/errors.js';
import { isString } from '../../../../base/common/types.js';

const DEFAULT_ACCOUNT_SIGN_IN_COMMAND = 'workbench.actions.accounts.signIn';
var DefaultAccountStatus;
(function (DefaultAccountStatus) {
    DefaultAccountStatus["Uninitialized"] = "uninitialized";
    DefaultAccountStatus["Unavailable"] = "unavailable";
    DefaultAccountStatus["Available"] = "available";
})(DefaultAccountStatus || (DefaultAccountStatus = {}));
const CONTEXT_DEFAULT_ACCOUNT_STATE = ( new RawContextKey('defaultAccountStatus', DefaultAccountStatus.Uninitialized));
class NullDefaultAccountService extends Disposable {
    constructor() {
        super(...arguments);
        this.onDidChangeDefaultAccount = Event.None;
    }
    async getDefaultAccount() {
        return null;
    }
    setDefaultAccount(account) {
    }
}
(class DefaultAccountManagementContribution extends Disposable {
    static { this.ID = 'workbench.contributions.defaultAccountManagement'; }
    constructor(defaultAccountService, configurationService, authenticationService, extensionService, productService, requestService, logService, contextKeyService) {
        super();
        this.defaultAccountService = defaultAccountService;
        this.configurationService = configurationService;
        this.authenticationService = authenticationService;
        this.extensionService = extensionService;
        this.productService = productService;
        this.requestService = requestService;
        this.logService = logService;
        this.defaultAccount = null;
        this.accountStatusContext = CONTEXT_DEFAULT_ACCOUNT_STATE.bindTo(contextKeyService);
        this.initialize();
    }
    async initialize() {
        this.logService.debug('[DefaultAccount] Starting initialization');
        if (!this.productService.defaultAccount) {
            this.logService.debug('[DefaultAccount] No default account configuration in product service, skipping initialization');
            return;
        }
        const defaultAccountProviderId = this.getDefaultAccountProviderId();
        this.logService.debug('[DefaultAccount] Default account provider ID:', defaultAccountProviderId);
        if (!defaultAccountProviderId) {
            return;
        }
        await this.extensionService.whenInstalledExtensionsRegistered();
        this.logService.debug('[DefaultAccount] Installed extensions registered.');
        const declaredProvider = this.authenticationService.declaredProviders.find(provider => provider.id === defaultAccountProviderId);
        if (!declaredProvider) {
            this.logService.info(`[DefaultAccount] Authentication provider is not declared.`, defaultAccountProviderId);
            return;
        }
        this.registerSignInAction(defaultAccountProviderId, this.productService.defaultAccount.authenticationProvider.scopes);
        this.setDefaultAccount(await this.getDefaultAccountFromAuthenticatedSessions(defaultAccountProviderId, this.productService.defaultAccount.authenticationProvider.scopes));
        this._register(this.authenticationService.onDidChangeSessions(async (e) => {
            if (e.providerId !== this.getDefaultAccountProviderId()) {
                return;
            }
            if (this.defaultAccount && e.event.removed?.some(session => session.id === this.defaultAccount?.sessionId)) {
                this.setDefaultAccount(null);
                return;
            }
            this.setDefaultAccount(await this.getDefaultAccountFromAuthenticatedSessions(defaultAccountProviderId, this.productService.defaultAccount.authenticationProvider.scopes));
        }));
        this.logService.debug('[DefaultAccount] Initialization complete');
    }
    setDefaultAccount(account) {
        this.defaultAccount = account;
        this.defaultAccountService.setDefaultAccount(this.defaultAccount);
        if (this.defaultAccount) {
            this.accountStatusContext.set(DefaultAccountStatus.Available);
            this.logService.debug('[DefaultAccount] Account status set to Available');
        }
        else {
            this.accountStatusContext.set(DefaultAccountStatus.Unavailable);
            this.logService.debug('[DefaultAccount] Account status set to Unavailable');
        }
    }
    extractFromToken(token) {
        const result = ( new Map());
        const firstPart = token?.split(':')[0];
        const fields = firstPart?.split(';');
        for (const field of fields) {
            const [key, value] = field.split('=');
            result.set(key, value);
        }
        this.logService.debug(`[DefaultAccount] extractFromToken: ${JSON.stringify(Object.fromEntries(result))}`);
        return result;
    }
    async getDefaultAccountFromAuthenticatedSessions(authProviderId, scopes) {
        try {
            this.logService.debug('[DefaultAccount] Getting Default Account from authenticated sessions for provider:', authProviderId);
            const sessions = await this.authenticationService.getSessions(authProviderId, undefined, undefined, true);
            const session = sessions.find(s => this.scopesMatch(s.scopes, scopes));
            if (!session) {
                this.logService.debug('[DefaultAccount] No matching session found for provider:', authProviderId);
                return null;
            }
            const [chatEntitlements, tokenEntitlements] = await Promise.all([
                this.getChatEntitlements(session.accessToken),
                this.getTokenEntitlements(session.accessToken),
            ]);
            const mcpRegistryProvider = tokenEntitlements.mcp ? await this.getMcpRegistryProvider(session.accessToken) : undefined;
            const account = {
                sessionId: session.id,
                enterprise: this.isEnterpriseAuthenticationProvider(authProviderId) || session.account.label.includes('_'),
                ...chatEntitlements,
                ...tokenEntitlements,
                mcpRegistryUrl: mcpRegistryProvider?.url,
                mcpAccess: mcpRegistryProvider?.registry_access,
            };
            this.logService.debug('[DefaultAccount] Successfully created default account for provider:', authProviderId);
            return account;
        }
        catch (error) {
            this.logService.error('[DefaultAccount] Failed to create default account for provider:', authProviderId, getErrorMessage(error));
            return null;
        }
    }
    scopesMatch(scopes, expectedScopes) {
        return scopes.length === expectedScopes.length && expectedScopes.every(scope => scopes.includes(scope));
    }
    async getTokenEntitlements(accessToken) {
        const tokenEntitlementsUrl = this.getTokenEntitlementUrl();
        if (!tokenEntitlementsUrl) {
            this.logService.debug('[DefaultAccount] No token entitlements URL found');
            return {};
        }
        this.logService.debug('[DefaultAccount] Fetching token entitlements from:', tokenEntitlementsUrl);
        try {
            const chatContext = await this.requestService.request({
                type: 'GET',
                url: tokenEntitlementsUrl,
                disableCache: true,
                headers: {
                    'Authorization': `Bearer ${accessToken}`
                }
            }, CancellationToken.None);
            const chatData = await asJson(chatContext);
            if (chatData) {
                const tokenMap = this.extractFromToken(chatData.token);
                return {
                    chat_preview_features_enabled: tokenMap.get('editor_preview_features') !== '0',
                    chat_agent_enabled: tokenMap.get('agent_mode') !== '0',
                    mcp: tokenMap.get('mcp') !== '0',
                };
            }
            this.logService.error('Failed to fetch token entitlements', 'No data returned');
        }
        catch (error) {
            this.logService.error('Failed to fetch token entitlements', getErrorMessage(error));
        }
        return {};
    }
    async getChatEntitlements(accessToken) {
        const chatEntitlementsUrl = this.getChatEntitlementUrl();
        if (!chatEntitlementsUrl) {
            this.logService.debug('[DefaultAccount] No chat entitlements URL found');
            return {};
        }
        this.logService.debug('[DefaultAccount] Fetching chat entitlements from:', chatEntitlementsUrl);
        try {
            const context = await this.requestService.request({
                type: 'GET',
                url: chatEntitlementsUrl,
                disableCache: true,
                headers: {
                    'Authorization': `Bearer ${accessToken}`
                }
            }, CancellationToken.None);
            const data = await asJson(context);
            if (data) {
                return data;
            }
            this.logService.error('Failed to fetch entitlements', 'No data returned');
        }
        catch (error) {
            this.logService.error('Failed to fetch entitlements', getErrorMessage(error));
        }
        return {};
    }
    async getMcpRegistryProvider(accessToken) {
        const mcpRegistryDataUrl = this.getMcpRegistryDataUrl();
        if (!mcpRegistryDataUrl) {
            this.logService.debug('[DefaultAccount] No MCP registry data URL found');
            return undefined;
        }
        try {
            const context = await this.requestService.request({
                type: 'GET',
                url: mcpRegistryDataUrl,
                disableCache: true,
                headers: {
                    'Authorization': `Bearer ${accessToken}`
                }
            }, CancellationToken.None);
            const data = await asJson(context);
            if (data) {
                this.logService.debug('Fetched MCP registry providers', data.mcp_registries);
                return data.mcp_registries[0];
            }
            this.logService.debug('Failed to fetch MCP registry providers', 'No data returned');
        }
        catch (error) {
            this.logService.error('Failed to fetch MCP registry providers', getErrorMessage(error));
        }
        return undefined;
    }
    getChatEntitlementUrl() {
        if (!this.productService.defaultAccount) {
            return undefined;
        }
        if (this.isEnterpriseAuthenticationProvider(this.getDefaultAccountProviderId())) {
            try {
                const enterpriseUrl = this.getEnterpriseUrl();
                if (!enterpriseUrl) {
                    return undefined;
                }
                return `${enterpriseUrl.protocol}//api.${enterpriseUrl.hostname}${enterpriseUrl.port ? ':' + enterpriseUrl.port : ''}/copilot_internal/user`;
            }
            catch (error) {
                this.logService.error(error);
            }
        }
        return this.productService.defaultAccount?.chatEntitlementUrl;
    }
    getTokenEntitlementUrl() {
        if (!this.productService.defaultAccount) {
            return undefined;
        }
        if (this.isEnterpriseAuthenticationProvider(this.getDefaultAccountProviderId())) {
            try {
                const enterpriseUrl = this.getEnterpriseUrl();
                if (!enterpriseUrl) {
                    return undefined;
                }
                return `${enterpriseUrl.protocol}//api.${enterpriseUrl.hostname}${enterpriseUrl.port ? ':' + enterpriseUrl.port : ''}/copilot_internal/v2/token`;
            }
            catch (error) {
                this.logService.error(error);
            }
        }
        return this.productService.defaultAccount?.tokenEntitlementUrl;
    }
    getMcpRegistryDataUrl() {
        if (!this.productService.defaultAccount) {
            return undefined;
        }
        if (this.isEnterpriseAuthenticationProvider(this.getDefaultAccountProviderId())) {
            try {
                const enterpriseUrl = this.getEnterpriseUrl();
                if (!enterpriseUrl) {
                    return undefined;
                }
                return `${enterpriseUrl.protocol}//api.${enterpriseUrl.hostname}${enterpriseUrl.port ? ':' + enterpriseUrl.port : ''}/copilot/mcp_registry`;
            }
            catch (error) {
                this.logService.error(error);
            }
        }
        return this.productService.defaultAccount?.mcpRegistryDataUrl;
    }
    getDefaultAccountProviderId() {
        if (this.productService.defaultAccount && this.configurationService.getValue(this.productService.defaultAccount.authenticationProvider.enterpriseProviderConfig) === this.productService.defaultAccount?.authenticationProvider.enterpriseProviderId) {
            return this.productService.defaultAccount?.authenticationProvider.enterpriseProviderId;
        }
        return this.productService.defaultAccount?.authenticationProvider.id;
    }
    isEnterpriseAuthenticationProvider(providerId) {
        if (!providerId) {
            return false;
        }
        return providerId === this.productService.defaultAccount?.authenticationProvider.enterpriseProviderId;
    }
    getEnterpriseUrl() {
        if (!this.productService.defaultAccount) {
            return undefined;
        }
        const value = this.configurationService.getValue(this.productService.defaultAccount.authenticationProvider.enterpriseProviderUriSetting);
        if (!isString(value)) {
            return undefined;
        }
        return ( new URL(value));
    }
    registerSignInAction(authProviderId, scopes) {
        const that = this;
        this._register(registerAction2(class extends Action2 {
            constructor() {
                super({
                    id: DEFAULT_ACCOUNT_SIGN_IN_COMMAND,
                    title: ( localize(13370, "Sign in")),
                });
            }
            run() {
                return that.authenticationService.createSession(authProviderId, scopes);
            }
        }));
    }
});

export { DEFAULT_ACCOUNT_SIGN_IN_COMMAND, NullDefaultAccountService };
