"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MergeWithExisting = void 0;
/* eslint-disable @typescript-eslint/no-non-null-assertion */
const errors_js_1 = require("../../errors.js");
const parsing_js_1 = require("../configure/parsing.js");
class MergeWithExisting {
    static schema(current, update) {
        if (update === undefined)
            return current;
        if (update.description !== undefined)
            current.description = update.description;
        if (update.propertyDescriptions !== undefined)
            current.properties = MergeWithExisting.properties(current.properties, update.propertyDescriptions);
        if (update.generative !== undefined)
            current.moduleConfig = MergeWithExisting.generative(current.moduleConfig, update.generative);
        if (update.invertedIndex !== undefined)
            current.invertedIndexConfig = MergeWithExisting.invertedIndex(current.invertedIndexConfig, update.invertedIndex);
        if (update.multiTenancy !== undefined)
            current.multiTenancyConfig = MergeWithExisting.multiTenancy(current.multiTenancyConfig, update.multiTenancy);
        if (update.objectTTL !== undefined) {
            current.objectTtlConfig = MergeWithExisting.objectTTL(current.objectTtlConfig, update.objectTTL);
        }
        if (update.replication !== undefined)
            current.replicationConfig = MergeWithExisting.replication(current.replicationConfig, update.replication);
        if (update.reranker !== undefined)
            current.moduleConfig = MergeWithExisting.reranker(current.moduleConfig, update.reranker);
        if (update.vectorizers !== undefined) {
            if (Array.isArray(update.vectorizers)) {
                current.vectorConfig = MergeWithExisting.vectors(current.vectorConfig, update.vectorizers);
            }
            else if (current.vectorConfig !== undefined) {
                const updateVectorizers = {
                    ...update.vectorizers,
                    name: 'default',
                };
                current.vectorConfig = MergeWithExisting.vectors(current.vectorConfig, [updateVectorizers]);
            }
            else {
                current.vectorIndexConfig =
                    update.vectorizers?.vectorIndex.name === 'hnsw'
                        ? MergeWithExisting.hnsw(current.vectorIndexConfig, update.vectorizers.vectorIndex.config)
                        : MergeWithExisting.flat(current.vectorIndexConfig, update.vectorizers.vectorIndex.config);
            }
        }
        return current;
    }
    static properties(current, update) {
        if (current === undefined)
            throw Error('Properties are missing from the class schema.');
        if (current.length === 0)
            return current;
        return current.map((property) => ({
            ...property,
            description: update[property.name] ?? property.description,
        }));
    }
    static generative(current, update) {
        if (current === undefined)
            throw Error('Module config is missing from the class schema.');
        if (update === undefined)
            return current;
        const generative = update.name === 'generative-azure-openai' ? 'generative-openai' : update.name;
        const old = Object.keys(current).find((key) => key.startsWith('generative-') && key !== update.name);
        if (old !== undefined) {
            delete current[old];
        }
        const currentGenerative = current[generative] || {};
        current[generative] = {
            ...currentGenerative,
            ...update.config,
        };
        return current;
    }
    static reranker(current, update) {
        if (current === undefined)
            throw Error('Module config is missing from the class schema.');
        if (update === undefined)
            return current;
        const reranker = current[update.name];
        const old = Object.keys(current).find((key) => key.startsWith('reranker-') && key !== update.name);
        if (old !== undefined) {
            delete current[old];
        }
        current[update.name] = {
            ...reranker,
            ...update.config,
        };
        return current;
    }
    static invertedIndex(current, update) {
        if (current === undefined)
            throw Error('Inverted index config is missing from the class schema.');
        if (update === undefined)
            return current;
        const { bm25, stopwords, ...rest } = update;
        const merged = { ...current, ...rest };
        if (bm25 !== undefined)
            merged.bm25 = { ...current.bm25, ...bm25 };
        if (stopwords !== undefined)
            merged.stopwords = { ...current.stopwords, ...stopwords };
        return merged;
    }
    static objectTTL(current, update) {
        if (current === undefined)
            throw Error('Object TTL config is missing from the class schema.');
        return {
            enabled: update.enabled ?? current.enabled,
            deleteOn: update.deleteOn ?? current.deleteOn,
            defaultTtl: update.defaultTTLSeconds ?? current.defaultTtl,
            filterExpiredObjects: update.filterExpiredObjects ?? current.filterExpiredObjects,
        };
    }
    static multiTenancy(current, update) {
        if (current === undefined)
            throw Error('Multi-tenancy config is missing from the class schema.');
        return { ...current, ...update };
    }
    static replication(current, update) {
        if (current === undefined)
            throw Error('Replication config is missing from the class schema.');
        return { ...current, ...update };
    }
    static vectors(current, update) {
        if (current === undefined)
            throw Error('Vector index config is missing from the class schema.');
        update.forEach((v) => {
            const existing = current[v.name];
            if (existing !== undefined) {
                current[v.name].vectorIndexConfig =
                    v.vectorIndex.name === 'hnsw'
                        ? MergeWithExisting.hnsw(existing.vectorIndexConfig, v.vectorIndex.config)
                        : MergeWithExisting.flat(existing.vectorIndexConfig, v.vectorIndex.config);
            }
        });
        return current;
    }
    static flat(current, update) {
        if ((parsing_js_1.QuantizerGuards.isPQUpdate(update.quantizer) && (current?.bq).enabled) ||
            (parsing_js_1.QuantizerGuards.isBQUpdate(update.quantizer) && (current?.pq).enabled))
            throw Error(`Cannot update the quantizer type of an enabled vector index.`);
        const { quantizer, ...rest } = update;
        const merged = { ...current, ...rest };
        if (parsing_js_1.QuantizerGuards.isBQUpdate(quantizer)) {
            const { type, ...quant } = quantizer;
            merged.bq = { ...current.bq, ...quant, enabled: true };
        }
        return merged;
    }
    static hnsw(current, update) {
        const hasOtherQuantizerAlready = (quantizer) => ['pq', 'bq', 'sq', 'rq'].some((q) => q !== quantizer && current?.[q]?.enabled);
        if ((parsing_js_1.QuantizerGuards.isBQUpdate(update.quantizer) && hasOtherQuantizerAlready('bq')) ||
            (parsing_js_1.QuantizerGuards.isPQUpdate(update.quantizer) && hasOtherQuantizerAlready('pq')) ||
            (parsing_js_1.QuantizerGuards.isSQUpdate(update.quantizer) && hasOtherQuantizerAlready('sq')) ||
            (parsing_js_1.QuantizerGuards.isRQUpdate(update.quantizer) && hasOtherQuantizerAlready('rq'))) {
            throw new errors_js_1.WeaviateInvalidInputError(`Cannot update the quantizer type of an enabled vector index.`);
        }
        const { quantizer, ...rest } = update;
        const merged = { ...current, ...rest };
        if (parsing_js_1.QuantizerGuards.isBQUpdate(quantizer)) {
            const { type, ...quant } = quantizer;
            merged.bq = { ...current.bq, ...quant, enabled: true };
        }
        if (parsing_js_1.QuantizerGuards.isPQUpdate(quantizer)) {
            const { type, ...quant } = quantizer;
            merged.pq = { ...current.pq, ...quant, enabled: true };
        }
        if (parsing_js_1.QuantizerGuards.isSQUpdate(quantizer)) {
            const { type, ...quant } = quantizer;
            merged.sq = { ...current.sq, ...quant, enabled: true };
        }
        if (parsing_js_1.QuantizerGuards.isRQUpdate(quantizer)) {
            const { type, ...quant } = quantizer;
            merged.rq = { ...current.rq, ...quant, enabled: true };
        }
        return merged;
    }
}
exports.MergeWithExisting = MergeWithExisting;
