import { __decorate, __param } from '../../../../../../external/tslib/tslib.es6.js';
import { coalesce } from '../../../base/common/arrays.js';
import { Emitter, Event } from '../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import { equals } from '../../../base/common/objects.js';
import { isEmptyObject } from '../../../base/common/types.js';
import { ConfigurationModel } from './configurationModels.js';
import { Extensions } from './configurationRegistry.js';
import { ILogService } from '../../log/common/log.service.js';
import { IPolicyService } from '../../policy/common/policy.service.js';
import { Registry } from '../../registry/common/platform.js';
let DefaultConfiguration$1 = class DefaultConfiguration extends Disposable {
    constructor() {
        super(...arguments);
        this._onDidChangeConfiguration = this._register(( new Emitter()));
        this.onDidChangeConfiguration = this._onDidChangeConfiguration.event;
        this._configurationModel = ( new ConfigurationModel());
    }
    get configurationModel() {
        return this._configurationModel;
    }
    async initialize() {
        this.resetConfigurationModel();
        this._register(( Registry.as(Extensions.Configuration)).onDidUpdateConfiguration(({ properties, defaultsOverrides }) => this.onDidUpdateConfiguration(Array.from(properties), defaultsOverrides)));
        return this.configurationModel;
    }
    reload() {
        this.resetConfigurationModel();
        return this.configurationModel;
    }
    onDidUpdateConfiguration(properties, defaultsOverrides) {
        this.updateConfigurationModel(properties, ( Registry.as(Extensions.Configuration)).getConfigurationProperties());
        this._onDidChangeConfiguration.fire({ defaults: this.configurationModel, properties });
    }
    getConfigurationDefaultOverrides() {
        return {};
    }
    resetConfigurationModel() {
        this._configurationModel = ( new ConfigurationModel());
        const properties = ( Registry.as(Extensions.Configuration)).getConfigurationProperties();
        this.updateConfigurationModel(( Object.keys(properties)), properties);
    }
    updateConfigurationModel(properties, configurationProperties) {
        const configurationDefaultsOverrides = this.getConfigurationDefaultOverrides();
        for (const key of properties) {
            const defaultOverrideValue = configurationDefaultsOverrides[key];
            const propertySchema = configurationProperties[key];
            if (defaultOverrideValue !== undefined) {
                this._configurationModel.addValue(key, defaultOverrideValue);
            }
            else if (propertySchema) {
                this._configurationModel.addValue(key, propertySchema.default);
            }
            else {
                this._configurationModel.removeValue(key);
            }
        }
    }
};
class NullPolicyConfiguration {
    constructor() {
        this.onDidChangeConfiguration = Event.None;
        this.configurationModel = ( new ConfigurationModel());
    }
    async initialize() { return this.configurationModel; }
}
let PolicyConfiguration = class PolicyConfiguration extends Disposable {
    get configurationModel() { return this._configurationModel; }
    constructor(defaultConfiguration, policyService, logService) {
        super();
        this.defaultConfiguration = defaultConfiguration;
        this.policyService = policyService;
        this.logService = logService;
        this._onDidChangeConfiguration = this._register(( new Emitter()));
        this.onDidChangeConfiguration = this._onDidChangeConfiguration.event;
        this._configurationModel = ( new ConfigurationModel());
    }
    async initialize() {
        this.logService.trace('PolicyConfiguration#initialize');
        this.update(await this.updatePolicyDefinitions(this.defaultConfiguration.configurationModel.keys), false);
        this._register(this.policyService.onDidChange(policyNames => this.onDidChangePolicies(policyNames)));
        this._register(this.defaultConfiguration.onDidChangeConfiguration(async ({ properties }) => this.update(await this.updatePolicyDefinitions(properties), true)));
        return this._configurationModel;
    }
    async updatePolicyDefinitions(properties) {
        this.logService.trace('PolicyConfiguration#updatePolicyDefinitions', properties);
        const policyDefinitions = {};
        const keys = [];
        const configurationProperties = ( Registry.as(Extensions.Configuration)).getConfigurationProperties();
        for (const key of properties) {
            const config = configurationProperties[key];
            if (!config) {
                keys.push(key);
                continue;
            }
            if (config.policy) {
                if (config.type !== 'string' && config.type !== 'number') {
                    this.logService.warn(`Policy ${config.policy.name} has unsupported type ${config.type}`);
                    continue;
                }
                keys.push(key);
                policyDefinitions[config.policy.name] = { type: config.type };
            }
        }
        if (!isEmptyObject(policyDefinitions)) {
            await this.policyService.updatePolicyDefinitions(policyDefinitions);
        }
        return keys;
    }
    onDidChangePolicies(policyNames) {
        this.logService.trace('PolicyConfiguration#onDidChangePolicies', policyNames);
        const policyConfigurations = ( Registry.as(Extensions.Configuration)).getPolicyConfigurations();
        const keys = coalesce(( policyNames.map(policyName => policyConfigurations.get(policyName))));
        this.update(keys, true);
    }
    update(keys, trigger) {
        this.logService.trace('PolicyConfiguration#update', keys);
        const configurationProperties = ( Registry.as(Extensions.Configuration)).getConfigurationProperties();
        const changed = [];
        const wasEmpty = this._configurationModel.isEmpty();
        for (const key of keys) {
            const policyName = configurationProperties[key]?.policy?.name;
            if (policyName) {
                const policyValue = this.policyService.getPolicyValue(policyName);
                if (wasEmpty ? policyValue !== undefined : !equals(this._configurationModel.getValue(key), policyValue)) {
                    changed.push([key, policyValue]);
                }
            }
            else {
                if (this._configurationModel.getValue(key) !== undefined) {
                    changed.push([key, undefined]);
                }
            }
        }
        if (changed.length) {
            this.logService.trace('PolicyConfiguration#changed', changed);
            const old = this._configurationModel;
            this._configurationModel = ( new ConfigurationModel());
            for (const key of old.keys) {
                this._configurationModel.setValue(key, old.getValue(key));
            }
            for (const [key, policyValue] of changed) {
                if (policyValue === undefined) {
                    this._configurationModel.removeValue(key);
                }
                else {
                    this._configurationModel.setValue(key, policyValue);
                }
            }
            if (trigger) {
                this._onDidChangeConfiguration.fire(this._configurationModel);
            }
        }
    }
};
PolicyConfiguration = ( __decorate([
    ( __param(1, IPolicyService)),
    ( __param(2, ILogService))
], PolicyConfiguration));
export { DefaultConfiguration$1 as DefaultConfiguration, NullPolicyConfiguration, PolicyConfiguration };
