
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { Iterable } from '../../../../base/common/iterator.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import { LinkedList } from '../../../../base/common/linkedList.js';
import { isWeb } from '../../../../base/common/platform.js';
import { URI } from '../../../../base/common/uri.js';
import { ExternalUriOpenerPriority } from '../../../../editor/common/languages.js';
import { localize } from '../../../../nls.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.service.js';
import { ILogService } from '../../../../platform/log/common/log.service.js';
import { IOpenerService } from '../../../../platform/opener/common/opener.service.js';
import { IQuickInputService } from '../../../../platform/quickinput/common/quickInput.service.js';
import { defaultExternalUriOpenerId, externalUriOpenersSettingId } from './configuration.js';
import { testUrlMatchesGlob } from '../../../../platform/url/common/urlGlob.js';
import { IPreferencesService } from '../../../services/preferences/common/preferences.service.js';

let ExternalUriOpenerService = class ExternalUriOpenerService extends Disposable {
    constructor(
        openerService,
        configurationService,
        logService,
        preferencesService,
        quickInputService
    ) {
        super();
        this.configurationService = configurationService;
        this.logService = logService;
        this.preferencesService = preferencesService;
        this.quickInputService = quickInputService;
        this._providers = ( new LinkedList());
        this._register(openerService.registerExternalOpener(this));
    }
    registerExternalOpenerProvider(provider) {
        const remove = this._providers.push(provider);
        return {
            dispose: remove
        };
    }
    async getOpeners(targetUri, allowOptional, ctx, token) {
        const allOpeners = await this.getAllOpenersForUri(targetUri);
        if (allOpeners.size === 0) {
            return [];
        }
        if (ctx.preferredOpenerId) {
            if (ctx.preferredOpenerId === defaultExternalUriOpenerId) {
                return [];
            }
            const preferredOpener = allOpeners.get(ctx.preferredOpenerId);
            if (preferredOpener) {
                return [preferredOpener];
            }
        }
        const configuredOpener = this.getConfiguredOpenerForUri(allOpeners, targetUri);
        if (configuredOpener) {
            return configuredOpener === defaultExternalUriOpenerId ? [] : [configuredOpener];
        }
        const validOpeners = [];
        await Promise.all(( Array.from(( allOpeners.values())).map(async opener => {
            let priority;
            try {
                priority = await opener.canOpen(ctx.sourceUri, token);
            } catch (e) {
                this.logService.error(e);
                return;
            }
            switch (priority) {
            case ExternalUriOpenerPriority.Option:
            case ExternalUriOpenerPriority.Default:
            case ExternalUriOpenerPriority.Preferred:
                validOpeners.push({
                    opener,
                    priority
                });
                break;
            }
        })));
        if (validOpeners.length === 0) {
            return [];
        }
        const preferred = validOpeners.filter(x => x.priority === ExternalUriOpenerPriority.Preferred).at(0);
        if (preferred) {
            return [preferred.opener];
        }
        if (!allowOptional && validOpeners.every(x => x.priority === ExternalUriOpenerPriority.Option)) {
            return [];
        }
        return ( validOpeners.map(value => value.opener));
    }
    async openExternal(href, ctx, token) {
        const targetUri = typeof href === "string" ? ( URI.parse(href)) : href;
        const allOpeners = await this.getOpeners(targetUri, false, ctx, token);
        if (allOpeners.length === 0) {
            return false;
        } else if (allOpeners.length === 1) {
            return allOpeners[0].openExternalUri(targetUri, ctx, token);
        }
        return this.showOpenerPrompt(allOpeners, targetUri, ctx, token);
    }
    async getOpener(targetUri, ctx, token) {
        const allOpeners = await this.getOpeners(targetUri, true, ctx, token);
        if (allOpeners.length >= 1) {
            return allOpeners[0];
        }
        return undefined;
    }
    async getAllOpenersForUri(targetUri) {
        const allOpeners = ( new Map());
        await Promise.all(( Iterable.map(this._providers, async provider => {
            for await (const opener of provider.getOpeners(targetUri)) {
                allOpeners.set(opener.id, opener);
            }
        })));
        return allOpeners;
    }
    getConfiguredOpenerForUri(openers, targetUri) {
        const config = this.configurationService.getValue(externalUriOpenersSettingId) || {};
        for (const [uriGlob, id] of Object.entries(config)) {
            if (testUrlMatchesGlob(targetUri, uriGlob)) {
                if (id === defaultExternalUriOpenerId) {
                    return "default";
                }
                const entry = openers.get(id);
                if (entry) {
                    return entry;
                }
            }
        }
        return undefined;
    }
    async showOpenerPrompt(openers, targetUri, ctx, token) {
        const items = ( openers.map(opener => {
            return {
                label: opener.label,
                opener: opener
            };
        }));
        items.push({
            label: isWeb ? ( localize(10258, "Open in new browser window")) : ( localize(10259, "Open in default browser")),
            opener: undefined
        }, {
            type: "separator"
        }, {
            label: ( localize(10260, "Configure default opener...")),
            opener: "configureDefault"
        });
        const picked = await this.quickInputService.pick(items, {
            placeHolder: ( localize(10261, "How would you like to open: {0}", (targetUri.toString())))
        });
        if (!picked) {
            return true;
        }
        if (typeof picked.opener === "undefined") {
            return false;
        } else if (picked.opener === "configureDefault") {
            await this.preferencesService.openUserSettings({
                jsonEditor: true,
                revealSetting: {
                    key: externalUriOpenersSettingId,
                    edit: true
                }
            });
            return true;
        } else {
            return picked.opener.openExternalUri(targetUri, ctx, token);
        }
    }
};
ExternalUriOpenerService = ( __decorate([( __param(0, IOpenerService)), ( __param(1, IConfigurationService)), ( __param(2, ILogService)), ( __param(3, IPreferencesService)), ( __param(4, IQuickInputService))], ExternalUriOpenerService));

export { ExternalUriOpenerService };
