
import { ExtensionType, TargetPlatform } from './vscode/src/vs/platform/extensions/common/extensions.js';
import { IExtensionService } from './vscode/src/vs/workbench/services/extensions/common/extensions.service.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 { FileAccess, Schemas } from './vscode/src/vs/base/common/network.js';
import { ExtensionHostKind } from './vscode/src/vs/workbench/services/extensions/common/extensionHostKind.js';
import { IWorkbenchEnvironmentService } from './vscode/src/vs/workbench/services/environment/common/environmentService.service.js';
import { parse } from './vscode/src/vs/base/common/json.js';
import { IFileService } from './vscode/src/vs/platform/files/common/files.service.js';
import { IInstantiationService } from './vscode/src/vs/platform/instantiation/common/instantiation.js';
import { IWorkbenchExtensionEnablementService } from './vscode/src/vs/workbench/services/extensionManagement/common/extensionManagement.service.js';
import { StandaloneServices } from './vscode/src/vs/editor/standalone/browser/standaloneServices.js';
import { ExtensionManifestTranslator } from './vscode/src/vs/platform/extensionManagement/common/extensionsScannerService.js';
import { language } from './vscode/src/vs/base/common/platform.js';
import '@codingame/monaco-vscode-extensions-service-override';
import { registerExtensionFile, RegisteredUriFile, CustomSchemas } from '@codingame/monaco-vscode-files-service-override';
import { waitServicesReady } from './lifecycle.js';
import { throttle } from './tools.js';
import { getBuiltInExtensionTranslationsUris } from './l10n.js';

let apiFactory;
function registerLocalApiFactory(_apiFactory) {
    apiFactory = _apiFactory;
}
let defaultApiHandler;
function registerDefaultApiHandler(handler) {
    defaultApiHandler = handler;
}
function registerExtensionFileUrl(extensionLocation, filePath, url, metadataOrMimeType) {
    const fileDisposable = new DisposableStore();
    fileDisposable.add(FileAccess.registerStaticBrowserUri(joinPath(extensionLocation, filePath), URI.parse(url)));
    const metadata = typeof metadataOrMimeType === 'string' ? { mimeType: metadataOrMimeType } : metadataOrMimeType;
    fileDisposable.add(registerExtensionFile(new RegisteredUriFile(joinPath(extensionLocation, filePath), url, metadata)));
    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, ExtensionHostKind.Remote, { path: directory });
}
const forcedExtensionHostKinds = new Map();
const extensions = [];
function getExtensionManifests() {
    return extensions;
}
function getForcedExtensionHostKind(id) {
    return forcedExtensionHostKinds.get(id);
}
function registerExtension(manifest, extHostKind, { path = '/extension', 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 === ExtensionHostKind.Remote) {
            realLocation = URI.from({ scheme: Schemas.vscodeRemote, authority: remoteAuthority, path });
        }
        const instantiationService = StandaloneServices.get(IInstantiationService);
        const translator = instantiationService.createInstance(ExtensionManifestTranslator);
        const nlsConfiguration = {
            devMode: false,
            language: language,
            pseudo: language === 'pseudo',
            translations: getBuiltInExtensionTranslationsUris(language) ?? {}
        };
        const localizedManifest = await translator.translateManifest(realLocation, manifest, nlsConfiguration);
        const extension = {
            manifest: localizedManifest,
            type: system ? ExtensionType.System : ExtensionType.User,
            isBuiltin: true,
            identifier: { id },
            location: realLocation,
            targetPlatform: TargetPlatform.WEB,
            isValid: true,
            validations: [],
            extHostKind,
            readmeUrl: readmePath != null ? URI.joinPath(realLocation, readmePath) : undefined,
            changelogUrl: changelogPath != null ? URI.joinPath(realLocation, changelogPath) : undefined,
            preRelease: false
        };
        if (extHostKind != null) {
            forcedExtensionHostKinds.set(id, extHostKind);
        }
        if (extHostKind !== ExtensionHostKind.Remote) {
            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 !== ExtensionHostKind.Remote) {
        function registerFileUrl(path, url, metadataOrMimeType) {
            return registerExtensionFileUrl(location, path, url, metadataOrMimeType);
        }
        api = {
            ...api,
            registerFileUrl
        };
    }
    if (extHostKind === ExtensionHostKind.LocalProcess) {
        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 await apiFactory(id);
        }
        api = {
            ...api,
            getApi,
            async setAsDefaultApi() {
                defaultApiHandler?.(await getApi());
            }
        };
    }
    return api;
}

export { ExtensionHostKind, getExtensionManifests, getForcedExtensionHostKind, registerDefaultApiHandler, registerExtension, registerLocalApiFactory, registerRemoteExtension };
