import { IExtensionService } from './vscode/src/vs/workbench/services/extensions/common/extensions.js';
import { URI } from './vscode/src/vs/base/common/uri.js';
import { getExtensionId } from './vscode/src/vs/platform/extensionManagement/common/extensionManagementUtil.js';
import { DisposableStore } from './vscode/src/vs/base/common/lifecycle.js';
import { joinPath } from './vscode/src/vs/base/common/resources.js';
import { Schemas, FileAccess } from './vscode/src/vs/base/common/network.js';
export { ExtensionHostKind } from './vscode/src/vs/workbench/services/extensions/common/extensionHostKind.js';
import { IWorkbenchEnvironmentService } from './vscode/src/vs/workbench/services/environment/common/environmentService.js';
import { parse } from './vscode/src/vs/base/common/json.js';
import { IFileService } from './vscode/src/vs/platform/files/common/files.js';
import { IInstantiationService } from './vscode/src/vs/platform/instantiation/common/instantiation.js';
import { IWorkbenchExtensionEnablementService } from './vscode/src/vs/workbench/services/extensionManagement/common/extensionManagement.js';
import { StandaloneServices } from './vscode/src/vs/editor/standalone/browser/standaloneServices.js';
import { CustomSchemas, registerExtensionFile } from '@codingame/monaco-vscode-files-service-override';
import { waitServicesReady } from './lifecycle.js';
import { ExtensionManifestTranslator } from './tools/l10n.js';
import { throttle, memoized } from './tools.js';
import { setDefaultApi } from './api.js';
let apiFactory;
function registerLocalApiFactory(_apiFactory) {
    apiFactory = _apiFactory;
}
function registerExtensionFileUrl(extensionLocation, filePath, url, mimeType) {
    const fileDisposable = new DisposableStore();
    fileDisposable.add(FileAccess.registerStaticBrowserUri(joinPath(extensionLocation, filePath), ( URI.parse(url))));
    fileDisposable.add(registerExtensionFile(extensionLocation, filePath, memoized(async () => {
        const response = await fetch(url, {
            headers: mimeType != null
                ? {
                    Accept: mimeType
                }
                : {}
        });
        if (response.status !== 200) {
            throw new Error(response.statusText);
        }
        return new Uint8Array(await response.arrayBuffer());
    })));
    return fileDisposable;
}
const deltaExtensions = throttle(async ({ toAdd, toRemove }) => {
    await waitServicesReady();
    const extensionService = StandaloneServices.get(IExtensionService);
    await extensionService.deltaExtensions(toAdd, toRemove);
}, (a, b) => ({ toAdd: [...a.toAdd, ...b.toAdd], toRemove: [...a.toRemove, ...b.toRemove] }), 0);
async function registerRemoteExtension(directory) {
    await waitServicesReady();
    const fileService = StandaloneServices.get(IFileService);
    const remoteAuthority = StandaloneServices.get(IWorkbenchEnvironmentService).remoteAuthority;
    const content = await fileService.readFile(joinPath(( URI.from(
        { scheme: Schemas.vscodeRemote, authority: remoteAuthority, path: directory }
    )), 'package.json'));
    const manifest = parse(( content.value.toString()));
    return registerExtension(manifest, 3 , { path: directory });
}
const forcedExtensionHostKinds = new Map();
const extensions = [];
function getExtensionManifests() {
    return extensions;
}
function getForcedExtensionHostKind(id) {
    return forcedExtensionHostKinds.get(id);
}
function registerExtension(manifest, extHostKind, { path = '/', system = false, readmePath, changelogPath } = {}) {
    const id = getExtensionId(manifest.publisher, manifest.name);
    const location = ( URI.from({ scheme: CustomSchemas.extensionFile, authority: id, path }));
    const addExtensionPromise = (async () => {
        await waitServicesReady();
        const remoteAuthority = StandaloneServices.get(IWorkbenchEnvironmentService).remoteAuthority;
        let realLocation = location;
        if (extHostKind === 3 ) {
            realLocation = ( URI.from({ scheme: Schemas.vscodeRemote, authority: remoteAuthority, path }));
        }
        const instantiationService = StandaloneServices.get(IInstantiationService);
        const translator = instantiationService.createInstance(ExtensionManifestTranslator);
        const localizedManifest = await translator.translateManifest(realLocation, manifest);
        const extension = {
            manifest: localizedManifest,
            type: system ? 0  : 1 ,
            isBuiltin: true,
            identifier: { id },
            location: realLocation,
            targetPlatform: "web" ,
            isValid: true,
            validations: [],
            extHostKind,
            readmeUrl: readmePath != null ? URI.joinPath(realLocation, readmePath) : undefined,
            changelogUrl: changelogPath != null ? URI.joinPath(realLocation, changelogPath) : undefined
        };
        if (extHostKind != null) {
            forcedExtensionHostKinds.set(id, extHostKind);
        }
        if (extHostKind !== 3 ) {
            extensions.push(extension);
        }
        const extensionEnablementService = StandaloneServices.get(IWorkbenchExtensionEnablementService);
        if (extensionEnablementService.isEnabled(extension)) {
            await deltaExtensions({ toAdd: [extension], toRemove: [] });
        }
        return extension;
    })();
    let api = {
        id,
        async whenReady() {
            await addExtensionPromise;
        },
        async isEnabled() {
            await waitServicesReady();
            const extensionEnablementService = StandaloneServices.get(IWorkbenchExtensionEnablementService);
            const extension = await addExtensionPromise;
            return extensionEnablementService.isEnabled(extension);
        },
        async dispose() {
            const extension = await addExtensionPromise;
            const index = extensions.indexOf(extension);
            if (index >= 0) {
                extensions.splice(extensions.indexOf(extension), 1);
            }
            forcedExtensionHostKinds.delete(id);
            await deltaExtensions({ toAdd: [], toRemove: [extension] });
        }
    };
    if (extHostKind !== 3 ) {
        function registerFileUrl(path, url, mimeType) {
            return registerExtensionFileUrl(location, path, url, mimeType);
        }
        api = {
            ...api,
            registerFileUrl
        };
    }
    if (extHostKind === 1 ) {
        async function getApi() {
            await addExtensionPromise;
            if (apiFactory == null) {
                throw new Error('The local api can\'t be used without registering the local extension host by importing `vscode/localExtensionHost`');
            }
            return apiFactory(id);
        }
        api = {
            ...api,
            getApi,
            async setAsDefaultApi() {
                setDefaultApi(await getApi());
            }
        };
    }
    return api;
}
export { getExtensionManifests, getForcedExtensionHostKind, registerExtension, registerLocalApiFactory, registerRemoteExtension };
