// SPDX-License-Identifier: Apache-2.0
import { ReflectAssist } from '../../../business/utils/reflect-assist.js';
import { Comparators } from '../../../business/utils/comparators.js';
import { DuplicateConfigSourceError } from '../api/duplicate-config-source-error.js';
import { IllegalArgumentError } from '../../../business/errors/illegal-argument-error.js';
export class LayeredConfig {
    mergeSourceValues;
    _sources;
    constructor(sources, mergeSourceValues = false) {
        this.mergeSourceValues = mergeSourceValues;
        if (sources) {
            sources.sort(Comparators.configSource);
        }
        this._sources = sources ?? [];
    }
    get sources() {
        return [...this._sources];
    }
    addSource(source) {
        if (!source) {
            throw new IllegalArgumentError('source cannot be null or undefined');
        }
        if (this._sources.includes(source)) {
            throw new DuplicateConfigSourceError(source);
        }
        if (this._sources.some((s) => s.name === source.name && s.ordinal === source.ordinal)) {
            throw new DuplicateConfigSourceError(source);
        }
        this._sources.push(source);
        this._sources.sort(Comparators.configSource);
    }
    asBoolean(key) {
        return this.primitiveScalar(this.asBoolean, key, true);
    }
    asNumber(key) {
        return this.primitiveScalar(this.asNumber, key, 1);
    }
    asObject(cls, key) {
        return this.objectScalar(this.asObject, cls, key);
    }
    asObjectArray(cls, key) {
        return this.objectArray(this.asObjectArray, cls, key);
    }
    asString(key) {
        return this.primitiveScalar(this.asString, key, 'string');
    }
    asStringArray(key) {
        return this.primitiveScalar(this.asStringArray, key, ['stringArray']);
    }
    properties() {
        const finalMap = new Map();
        for (const source of this.sources) {
            const sourceProperties = source.properties();
            for (const [key, value] of sourceProperties.entries()) {
                finalMap.set(key, value);
            }
        }
        return finalMap;
    }
    propertyNames() {
        const finalSet = new Set();
        for (const source of this.sources) {
            const sourcePropertyNames = source.propertyNames();
            for (const key of sourcePropertyNames) {
                finalSet.add(key);
            }
        }
        return finalSet;
    }
    async refresh() {
        for (const source of this.sources) {
            if (ReflectAssist.isRefreshable(source)) {
                await source.refresh();
            }
        }
    }
    primitiveScalar(method, key, exampleInstance) {
        let value = undefined;
        let scalarType = typeof exampleInstance;
        if (Array.isArray(exampleInstance) && exampleInstance && exampleInstance.length > 0) {
            scalarType = typeof exampleInstance[0];
        }
        switch (scalarType) {
            case 'boolean':
            case 'number':
            case 'string': {
                break;
            }
            default: {
                throw new IllegalArgumentError(`Unsupported scalar type: ${scalarType}`);
            }
        }
        for (const source of this.sources) {
            const currentValue = source[method.name](key);
            if (currentValue !== null && currentValue !== undefined) {
                value = currentValue;
            }
        }
        return value;
    }
    objectScalar(method, cls, key) {
        let value = undefined;
        for (const source of this.sources) {
            const currentValue = source[method.name](cls, key);
            if (currentValue !== null && currentValue !== undefined) {
                value = this.mergeSourceValues ? ReflectAssist.merge(value, currentValue) : currentValue;
            }
        }
        return value;
    }
    objectArray(method, cls, key) {
        let value = undefined;
        for (const source of this.sources) {
            const currentValue = source[method.name](cls, key);
            if (currentValue !== null && currentValue !== undefined) {
                value = currentValue;
            }
        }
        return value;
    }
}
//# sourceMappingURL=layered-config.js.map