import { distinct } from "../../../base/common/arrays.mjs";
import { Emitter } from "../../../base/common/event.mjs";
import { isString, isUndefinedOrNull, isUndefined } from "../../../base/common/types.mjs";
import { localize } from "../../../nls.mjs";
import { Extensions as Extensions$1 } from "../../jsonschemas/common/jsonContributionRegistry.mjs";
import { Registry } from "../../registry/common/platform.mjs";
const Extensions = {
  Configuration: "base.contributions.configuration"
};
const resourceLanguageSettingsSchemaId = "vscode://schemas/settings/resourceLanguage";
const contributionRegistry = Registry.as(Extensions$1.JSONContribution);
class ConfigurationRegistry {
  constructor() {
    this.overrideIdentifiers = /* @__PURE__ */ new Set();
    this._onDidSchemaChange = new Emitter();
    this._onDidUpdateConfiguration = new Emitter();
    this.configurationDefaultsOverrides = /* @__PURE__ */ new Map();
    this.defaultLanguageConfigurationOverridesNode = {
      id: "defaultOverrides",
      title: localize("defaultLanguageConfigurationOverrides.title", "Default Language Configuration Overrides"),
      properties: {}
    };
    this.configurationContributors = [this.defaultLanguageConfigurationOverridesNode];
    this.resourceLanguageSettingsSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: "Unknown editor configuration setting", allowTrailingCommas: true, allowComments: true };
    this.configurationProperties = {};
    this.excludedConfigurationProperties = {};
    contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
    this.registerOverridePropertyPatternKey();
  }
  registerConfiguration(configuration, validate = true) {
    this.registerConfigurations([configuration], validate);
  }
  registerConfigurations(configurations, validate = true) {
    const properties = this.doRegisterConfigurations(configurations, validate);
    contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
    this._onDidSchemaChange.fire();
    this._onDidUpdateConfiguration.fire({ properties });
  }
  registerDefaultConfigurations(configurationDefaults) {
    var _a;
    const properties = [];
    const overrideIdentifiers = [];
    for (const { overrides, source } of configurationDefaults) {
      for (const key in overrides) {
        properties.push(key);
        if (OVERRIDE_PROPERTY_REGEX.test(key)) {
          const defaultValue = Object.assign(Object.assign({}, ((_a = this.configurationDefaultsOverrides.get(key)) === null || _a === void 0 ? void 0 : _a.value) || {}), overrides[key]);
          this.configurationDefaultsOverrides.set(key, { source, value: defaultValue });
          const property = {
            type: "object",
            default: defaultValue,
            description: localize("defaultLanguageConfiguration.description", "Configure settings to be overridden for {0} language.", key),
            $ref: resourceLanguageSettingsSchemaId,
            defaultDefaultValue: defaultValue,
            source: isString(source) ? void 0 : source
          };
          overrideIdentifiers.push(...overrideIdentifiersFromKey(key));
          this.configurationProperties[key] = property;
          this.defaultLanguageConfigurationOverridesNode.properties[key] = property;
        } else {
          this.configurationDefaultsOverrides.set(key, { value: overrides[key], source });
          const property = this.configurationProperties[key];
          if (property) {
            this.updatePropertyDefaultValue(key, property);
            this.updateSchema(key, property);
          }
        }
      }
    }
    this.registerOverrideIdentifiers(overrideIdentifiers);
    this._onDidSchemaChange.fire();
    this._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });
  }
  registerOverrideIdentifiers(overrideIdentifiers) {
    for (const overrideIdentifier of overrideIdentifiers) {
      this.overrideIdentifiers.add(overrideIdentifier);
    }
    this.updateOverridePropertyPatternKey();
  }
  doRegisterConfigurations(configurations, validate) {
    const properties = [];
    configurations.forEach((configuration) => {
      properties.push(...this.validateAndRegisterProperties(configuration, validate, configuration.extensionInfo, configuration.restrictedProperties));
      this.configurationContributors.push(configuration);
      this.registerJSONConfiguration(configuration);
    });
    return properties;
  }
  validateAndRegisterProperties(configuration, validate = true, extensionInfo, restrictedProperties, scope = 3) {
    scope = isUndefinedOrNull(configuration.scope) ? scope : configuration.scope;
    let propertyKeys = [];
    let properties = configuration.properties;
    if (properties) {
      for (let key in properties) {
        if (validate && validateProperty(key)) {
          delete properties[key];
          continue;
        }
        const property = properties[key];
        property.source = extensionInfo;
        property.defaultDefaultValue = properties[key].default;
        this.updatePropertyDefaultValue(key, property);
        if (OVERRIDE_PROPERTY_REGEX.test(key)) {
          property.scope = void 0;
        } else {
          property.scope = isUndefinedOrNull(property.scope) ? scope : property.scope;
          property.restricted = isUndefinedOrNull(property.restricted) ? !!(restrictedProperties === null || restrictedProperties === void 0 ? void 0 : restrictedProperties.includes(key)) : property.restricted;
        }
        if (properties[key].hasOwnProperty("included") && !properties[key].included) {
          this.excludedConfigurationProperties[key] = properties[key];
          delete properties[key];
          continue;
        } else {
          this.configurationProperties[key] = properties[key];
        }
        if (!properties[key].deprecationMessage && properties[key].markdownDeprecationMessage) {
          properties[key].deprecationMessage = properties[key].markdownDeprecationMessage;
        }
        propertyKeys.push(key);
      }
    }
    let subNodes = configuration.allOf;
    if (subNodes) {
      for (let node of subNodes) {
        propertyKeys.push(...this.validateAndRegisterProperties(node, validate, extensionInfo, restrictedProperties, scope));
      }
    }
    return propertyKeys;
  }
  getConfigurationProperties() {
    return this.configurationProperties;
  }
  registerJSONConfiguration(configuration) {
    const register = (configuration2) => {
      let properties = configuration2.properties;
      if (properties) {
        for (const key in properties) {
          this.updateSchema(key, properties[key]);
        }
      }
      let subNodes = configuration2.allOf;
      if (subNodes) {
        subNodes.forEach(register);
      }
    };
    register(configuration);
  }
  updateSchema(key, property) {
    switch (property.scope) {
      case 1:
        break;
      case 2:
        break;
      case 6:
        break;
      case 3:
        break;
      case 4:
        break;
      case 5:
        this.resourceLanguageSettingsSchema.properties[key] = property;
        break;
    }
  }
  updateOverridePropertyPatternKey() {
    for (const overrideIdentifier of this.overrideIdentifiers.values()) {
      const overrideIdentifierProperty = `[${overrideIdentifier}]`;
      const resourceLanguagePropertiesSchema = {
        type: "object",
        description: localize("overrideSettings.defaultDescription", "Configure editor settings to be overridden for a language."),
        errorMessage: localize("overrideSettings.errorMessage", "This setting does not support per-language configuration."),
        $ref: resourceLanguageSettingsSchemaId
      };
      this.updatePropertyDefaultValue(overrideIdentifierProperty, resourceLanguagePropertiesSchema);
    }
    this._onDidSchemaChange.fire();
  }
  registerOverridePropertyPatternKey() {
    ({
      type: "object",
      description: localize("overrideSettings.defaultDescription", "Configure editor settings to be overridden for a language."),
      errorMessage: localize("overrideSettings.errorMessage", "This setting does not support per-language configuration."),
      $ref: resourceLanguageSettingsSchemaId
    });
    this._onDidSchemaChange.fire();
  }
  updatePropertyDefaultValue(key, property) {
    const configurationdefaultOverride = this.configurationDefaultsOverrides.get(key);
    let defaultValue = configurationdefaultOverride === null || configurationdefaultOverride === void 0 ? void 0 : configurationdefaultOverride.value;
    let defaultSource = configurationdefaultOverride === null || configurationdefaultOverride === void 0 ? void 0 : configurationdefaultOverride.source;
    if (isUndefined(defaultValue)) {
      defaultValue = property.defaultDefaultValue;
      defaultSource = void 0;
    }
    if (isUndefined(defaultValue)) {
      defaultValue = getDefaultValue(property.type);
    }
    property.default = defaultValue;
    property.defaultValueSource = defaultSource;
  }
}
const OVERRIDE_IDENTIFIER_PATTERN = `\\[([^\\]]+)\\]`;
const OVERRIDE_IDENTIFIER_REGEX = new RegExp(OVERRIDE_IDENTIFIER_PATTERN, "g");
const OVERRIDE_PROPERTY_PATTERN = `^(${OVERRIDE_IDENTIFIER_PATTERN})+$`;
const OVERRIDE_PROPERTY_REGEX = new RegExp(OVERRIDE_PROPERTY_PATTERN);
function overrideIdentifiersFromKey(key) {
  const identifiers = [];
  if (OVERRIDE_PROPERTY_REGEX.test(key)) {
    let matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
    while (matches === null || matches === void 0 ? void 0 : matches.length) {
      const identifier = matches[1].trim();
      if (identifier) {
        identifiers.push(identifier);
      }
      matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
    }
  }
  return distinct(identifiers);
}
function getDefaultValue(type) {
  const t = Array.isArray(type) ? type[0] : type;
  switch (t) {
    case "boolean":
      return false;
    case "integer":
    case "number":
      return 0;
    case "string":
      return "";
    case "array":
      return [];
    case "object":
      return {};
    default:
      return null;
  }
}
const configurationRegistry = new ConfigurationRegistry();
Registry.add(Extensions.Configuration, configurationRegistry);
function validateProperty(property) {
  if (!property.trim()) {
    return localize("config.property.empty", "Cannot register an empty property");
  }
  if (OVERRIDE_PROPERTY_REGEX.test(property)) {
    return localize("config.property.languageDefault", "Cannot register '{0}'. This matches property pattern '\\\\[.*\\\\]$' for describing language specific editor settings. Use 'configurationDefaults' contribution.", property);
  }
  if (configurationRegistry.getConfigurationProperties()[property] !== void 0) {
    return localize("config.property.duplicate", "Cannot register '{0}'. This property is already registered.", property);
  }
  return null;
}
export {
  Extensions,
  OVERRIDE_PROPERTY_PATTERN,
  OVERRIDE_PROPERTY_REGEX,
  getDefaultValue,
  overrideIdentifiersFromKey,
  resourceLanguageSettingsSchemaId,
  validateProperty
};
