
import { distinct } from '../../../base/common/arrays.js';
import { isString, isObject } from '../../../base/common/types.js';
import { localize } from '../../../nls.js';
import { Extensions, getAllConfigurationProperties, parseScope, ConfigurationScope, allSettings } from '../../configuration/common/configurationRegistry.js';
import { EXTENSION_IDENTIFIER_PATTERN } from '../../extensionManagement/common/extensionManagement.js';
import { Extensions as Extensions$1 } from '../../jsonschemas/common/jsonContributionRegistry.js';
import { Registry } from '../../registry/common/platform.js';

function getDisallowedIgnoredSettings() {
    const allSettings = ( Registry.as(Extensions.Configuration)).getConfigurationProperties();
    return ( Object.keys(allSettings)).filter(setting => !!allSettings[setting].disallowSyncIgnore);
}
function getDefaultIgnoredSettings(excludeExtensions = false) {
    const allSettings = ( Registry.as(Extensions.Configuration)).getConfigurationProperties();
    const ignoredSettings = getIgnoredSettings(allSettings, excludeExtensions);
    const disallowedSettings = getDisallowedIgnoredSettings();
    return distinct([...ignoredSettings, ...disallowedSettings]);
}
function getIgnoredSettingsForExtension(manifest) {
    if (!manifest.contributes?.configuration) {
        return [];
    }
    const configurations = Array.isArray(manifest.contributes.configuration) ? manifest.contributes.configuration : [manifest.contributes.configuration];
    if (!configurations.length) {
        return [];
    }
    const properties = getAllConfigurationProperties(configurations);
    return getIgnoredSettings(properties, false);
}
function getIgnoredSettings(properties, excludeExtensions) {
    const ignoredSettings = ( new Set());
    for (const key in properties) {
        if (excludeExtensions && !!properties[key].source) {
            continue;
        }
        const scope = isString(properties[key].scope) ? parseScope(properties[key].scope) : properties[key].scope;
        if (properties[key].ignoreSync || scope === ConfigurationScope.MACHINE || scope === ConfigurationScope.MACHINE_OVERRIDABLE) {
            ignoredSettings.add(key);
        }
    }
    return [...( ignoredSettings.values())];
}
const USER_DATA_SYNC_CONFIGURATION_SCOPE = "settingsSync";
const CONFIG_SYNC_KEYBINDINGS_PER_PLATFORM = "settingsSync.keybindingsPerPlatform";
function registerConfiguration() {
    const ignoredSettingsSchemaId = "vscode://schemas/ignoredSettings";
    const configurationRegistry = ( Registry.as(Extensions.Configuration));
    configurationRegistry.registerConfiguration({
        id: "settingsSync",
        order: 30,
        title: ( localize(2599, "Settings Sync")),
        type: "object",
        properties: {
            [CONFIG_SYNC_KEYBINDINGS_PER_PLATFORM]: {
                type: "boolean",
                description: ( localize(2600, "Synchronize keybindings for each platform.")),
                default: true,
                scope: ConfigurationScope.APPLICATION,
                tags: ["sync", "usesOnlineServices"]
            },
            "settingsSync.ignoredExtensions": {
                "type": "array",
                markdownDescription: ( localize(
                    2601,
                    "List of extensions to be ignored while synchronizing. The identifier of an extension is always `${publisher}.${name}`. For example: `vscode.csharp`."
                )),
                items: [{
                    type: "string",
                    pattern: EXTENSION_IDENTIFIER_PATTERN,
                    errorMessage: ( localize(2602, "Expected format '${publisher}.${name}'. Example: 'vscode.csharp'."))
                }],
                "default": [],
                "scope": ConfigurationScope.APPLICATION,
                uniqueItems: true,
                disallowSyncIgnore: true,
                tags: ["sync", "usesOnlineServices"]
            },
            "settingsSync.ignoredSettings": {
                "type": "array",
                description: ( localize(2603, "Configure settings to be ignored while synchronizing.")),
                "default": [],
                "scope": ConfigurationScope.APPLICATION,
                $ref: ignoredSettingsSchemaId,
                additionalProperties: true,
                uniqueItems: true,
                disallowSyncIgnore: true,
                tags: ["sync", "usesOnlineServices"]
            }
        }
    });
    const jsonRegistry = ( Registry.as(Extensions$1.JSONContribution));
    const registerIgnoredSettingsSchema = () => {
        const disallowedIgnoredSettings = getDisallowedIgnoredSettings();
        const defaultIgnoredSettings = getDefaultIgnoredSettings();
        const settings = ( Object.keys(allSettings.properties)).filter(setting => !defaultIgnoredSettings.includes(setting));
        const ignoredSettings = defaultIgnoredSettings.filter(setting => !disallowedIgnoredSettings.includes(setting));
        const ignoredSettingsSchema = {
            items: {
                type: "string",
                enum: [...settings, ...( ignoredSettings.map(setting => `-${setting}`))]
            }
        };
        jsonRegistry.registerSchema(ignoredSettingsSchemaId, ignoredSettingsSchema);
    };
    return configurationRegistry.onDidUpdateConfiguration(() => registerIgnoredSettingsSchema());
}
const NON_EXISTING_RESOURCE_REF = "0";
function isAuthenticationProvider(thing) {
    return thing && isObject(thing) && isString(thing.id) && Array.isArray(thing.scopes);
}
var SyncResource;
(function(SyncResource) {
    SyncResource["Settings"] = "settings";
    SyncResource["Keybindings"] = "keybindings";
    SyncResource["Snippets"] = "snippets";
    SyncResource["Prompts"] = "prompts";
    SyncResource["Tasks"] = "tasks";
    SyncResource["Mcp"] = "mcp";
    SyncResource["Extensions"] = "extensions";
    SyncResource["GlobalState"] = "globalState";
    SyncResource["Profiles"] = "profiles";
    SyncResource["WorkspaceState"] = "workspaceState";
})(SyncResource || (SyncResource = {}));
const ALL_SYNC_RESOURCES = [
    SyncResource.Settings,
    SyncResource.Keybindings,
    SyncResource.Snippets,
    SyncResource.Prompts,
    SyncResource.Tasks,
    SyncResource.Extensions,
    SyncResource.GlobalState,
    SyncResource.Profiles,
    SyncResource.Mcp
];
function getPathSegments(collection, ...paths) {
    return collection ? [collection, ...paths] : paths;
}
function getLastSyncResourceUri(collection, syncResource, environmentService, extUri) {
    return extUri.joinPath(
        environmentService.userDataSyncHome,
        ...getPathSegments(collection, syncResource, `lastSync${syncResource}.json`)
    );
}
function isUserDataManifest(thing) {
    return thing && isString(thing.session) && isString(thing.ref) && (isObject(thing.latest) || thing.latest === undefined) && (isObject(thing.collections) || thing.collections === undefined);
}
const HEADER_OPERATION_ID = "x-operation-id";
const HEADER_EXECUTION_ID = "X-Execution-Id";
function createSyncHeaders(executionId) {
    const headers = {};
    headers[HEADER_EXECUTION_ID] = executionId;
    return headers;
}
var UserDataSyncErrorCode;
(function(UserDataSyncErrorCode) {
    UserDataSyncErrorCode["Unauthorized"] = "Unauthorized";
    UserDataSyncErrorCode["Forbidden"] = "Forbidden";
    UserDataSyncErrorCode["NotFound"] = "NotFound";
    UserDataSyncErrorCode["MethodNotFound"] = "MethodNotFound";
    UserDataSyncErrorCode["Conflict"] = "Conflict";
    UserDataSyncErrorCode["Gone"] = "Gone";
    UserDataSyncErrorCode["PreconditionFailed"] = "PreconditionFailed";
    UserDataSyncErrorCode["TooLarge"] = "TooLarge";
    UserDataSyncErrorCode["UpgradeRequired"] = "UpgradeRequired";
    UserDataSyncErrorCode["PreconditionRequired"] = "PreconditionRequired";
    UserDataSyncErrorCode["TooManyRequests"] = "RemoteTooManyRequests";
    UserDataSyncErrorCode["TooManyRequestsAndRetryAfter"] = "TooManyRequestsAndRetryAfter";
    UserDataSyncErrorCode["RequestFailed"] = "RequestFailed";
    UserDataSyncErrorCode["RequestCanceled"] = "RequestCanceled";
    UserDataSyncErrorCode["RequestTimeout"] = "RequestTimeout";
    UserDataSyncErrorCode["RequestProtocolNotSupported"] = "RequestProtocolNotSupported";
    UserDataSyncErrorCode["RequestPathNotEscaped"] = "RequestPathNotEscaped";
    UserDataSyncErrorCode["RequestHeadersNotObject"] = "RequestHeadersNotObject";
    UserDataSyncErrorCode["NoCollection"] = "NoCollection";
    UserDataSyncErrorCode["NoRef"] = "NoRef";
    UserDataSyncErrorCode["EmptyResponse"] = "EmptyResponse";
    UserDataSyncErrorCode["TurnedOff"] = "TurnedOff";
    UserDataSyncErrorCode["SessionExpired"] = "SessionExpired";
    UserDataSyncErrorCode["ServiceChanged"] = "ServiceChanged";
    UserDataSyncErrorCode["DefaultServiceChanged"] = "DefaultServiceChanged";
    UserDataSyncErrorCode["LocalTooManyProfiles"] = "LocalTooManyProfiles";
    UserDataSyncErrorCode["LocalTooManyRequests"] = "LocalTooManyRequests";
    UserDataSyncErrorCode["LocalPreconditionFailed"] = "LocalPreconditionFailed";
    UserDataSyncErrorCode["LocalInvalidContent"] = "LocalInvalidContent";
    UserDataSyncErrorCode["LocalError"] = "LocalError";
    UserDataSyncErrorCode["IncompatibleLocalContent"] = "IncompatibleLocalContent";
    UserDataSyncErrorCode["IncompatibleRemoteContent"] = "IncompatibleRemoteContent";
    UserDataSyncErrorCode["Unknown"] = "Unknown";
})(UserDataSyncErrorCode || (UserDataSyncErrorCode = {}));
class UserDataSyncError extends Error {
    constructor(message, code, resource, operationId) {
        super(message);
        this.code = code;
        this.resource = resource;
        this.operationId = operationId;
        this.name = `${this.code} (UserDataSyncError) syncResource:${this.resource || "unknown"} operationId:${this.operationId || "unknown"}`;
    }
}
class UserDataSyncStoreError extends UserDataSyncError {
    constructor(message, url, code, serverCode, operationId) {
        super(message, code, undefined, operationId);
        this.url = url;
        this.serverCode = serverCode;
    }
}
class UserDataAutoSyncError extends UserDataSyncError {
    constructor(message, code) {
        super(message, code);
    }
}
(function(UserDataSyncError) {
    function toUserDataSyncError(error) {
        if (error instanceof UserDataSyncError) {
            return error;
        }
        const match = /^(.+) \(UserDataSyncError\) syncResource:(.+) operationId:(.+)$/.exec(error.name);
        if (match && match[1]) {
            const syncResource = match[2] === "unknown" ? undefined : match[2];
            const operationId = match[3] === "unknown" ? undefined : match[3];
            return ( new UserDataSyncError(error.message, match[1], syncResource, operationId));
        }
        return ( new UserDataSyncError(error.message, UserDataSyncErrorCode.Unknown));
    }
    UserDataSyncError.toUserDataSyncError = toUserDataSyncError;
})(UserDataSyncError || (UserDataSyncError = {}));
var SyncStatus;
(function(SyncStatus) {
    SyncStatus["Uninitialized"] = "uninitialized";
    SyncStatus["Idle"] = "idle";
    SyncStatus["Syncing"] = "syncing";
    SyncStatus["HasConflicts"] = "hasConflicts";
})(SyncStatus || (SyncStatus = {}));
var Change;
(function(Change) {
    Change[Change["None"] = 0] = "None";
    Change[Change["Added"] = 1] = "Added";
    Change[Change["Modified"] = 2] = "Modified";
    Change[Change["Deleted"] = 3] = "Deleted";
})(Change || (Change = {}));
var MergeState;
(function(MergeState) {
    MergeState["Preview"] = "preview";
    MergeState["Conflict"] = "conflict";
    MergeState["Accepted"] = "accepted";
})(MergeState || (MergeState = {}));
const SYNC_SERVICE_URL_TYPE = "sync.store.url.type";
function getEnablementKey(resource) {
    return `sync.enable.${resource}`;
}
const USER_DATA_SYNC_LOG_ID = "userDataSync";
const USER_DATA_SYNC_SCHEME = "vscode-userdata-sync";
const PREVIEW_DIR_NAME = "preview";

export { ALL_SYNC_RESOURCES, CONFIG_SYNC_KEYBINDINGS_PER_PLATFORM, Change, HEADER_EXECUTION_ID, HEADER_OPERATION_ID, MergeState, NON_EXISTING_RESOURCE_REF, PREVIEW_DIR_NAME, SYNC_SERVICE_URL_TYPE, SyncResource, SyncStatus, USER_DATA_SYNC_CONFIGURATION_SCOPE, USER_DATA_SYNC_LOG_ID, USER_DATA_SYNC_SCHEME, UserDataAutoSyncError, UserDataSyncError, UserDataSyncErrorCode, UserDataSyncStoreError, createSyncHeaders, getDefaultIgnoredSettings, getDisallowedIgnoredSettings, getEnablementKey, getIgnoredSettingsForExtension, getLastSyncResourceUri, getPathSegments, isAuthenticationProvider, isUserDataManifest, registerConfiguration };
