/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { expect } from '@jest/globals';
import { LogService, AbstractPluginManager, promisify, } from '@finos/legend-shared';
import {} from '@finos/legend-shared/test';
import { GraphManagerState } from '../GraphManagerState.js';
import { SECTION_INDEX_ELEMENT_PATH } from '../../graph/MetaModelConst.js';
export class TEST__GraphManagerPluginManager extends AbstractPluginManager {
    loggerPlugins = [];
    pureProtocolProcessorPlugins = [];
    pureGraphManagerPlugins = [];
    pureGraphPlugins = [];
    registerLoggerPlugin(plugin) {
        this.loggerPlugins.push(plugin);
    }
    registerPureGraphManagerPlugin(plugin) {
        this.pureGraphManagerPlugins.push(plugin);
    }
    registerPureProtocolProcessorPlugin(plugin) {
        this.pureProtocolProcessorPlugins.push(plugin);
    }
    registerPureGraphPlugin(plugin) {
        this.pureGraphPlugins.push(plugin);
    }
    getPureGraphManagerPlugins() {
        return this.pureGraphManagerPlugins;
    }
    getPureProtocolProcessorPlugins() {
        return this.pureProtocolProcessorPlugins;
    }
    getPureGraphPlugins() {
        return this.pureGraphPlugins;
    }
    getLoggerPlugins() {
        return [...this.loggerPlugins];
    }
}
export const TEST__getTestGraphManagerState = (pluginManager, logService) => new GraphManagerState(pluginManager ?? new TEST__GraphManagerPluginManager(), logService ?? new LogService());
export const TEST__excludeSectionIndex = (entities) => entities.filter((entity) => entity.path !== SECTION_INDEX_ELEMENT_PATH);
export const TEST_DEBUG__expectToIncludeSameEntities = (expected, actual) => {
    for (const entity of expected) {
        expect(entity).toEqual(actual.find((entry) => entity.path === entry.path));
    }
    for (const entity of actual) {
        expect(entity).toEqual(expected.find((entry) => entity.path === entry.path));
    }
};
export const TEST__ensureObjectFieldsAreSortedAlphabetically = (obj) => {
    const checkObjectFieldsAreSortedAlphabetically = (_obj) => {
        if (Array.isArray(_obj)) {
            _obj.forEach((element) => {
                if (typeof element === 'object') {
                    checkObjectFieldsAreSortedAlphabetically(element);
                }
            });
        }
        else {
            expect(Object.keys(_obj)).toEqual(
            /**
             * NOTE: we cannot use `localeCompare` because it is not compatible with
             * the way the backend (i.e. Java's Jackson/GSON sort property fields, which
             * employees a sorting strategy based on ASCII value).
             * e.g. 'enumeration'.localeCompare('enumValueMapping') = -1
             * but 'E' < 'e' in terms of ASCII value.
             * Therefore, we should just uses string comparison here instead
             */
            Object.keys(_obj).sort((k1, k2) => (k1 > k2 ? 1 : k1 < k2 ? -1 : 0)));
            for (const prop in _obj) {
                if (Object.prototype.hasOwnProperty.call(_obj, prop)) {
                    const value = _obj[prop];
                    if (typeof value === 'object') {
                        checkObjectFieldsAreSortedAlphabetically(value);
                    }
                }
            }
        }
    };
    checkObjectFieldsAreSortedAlphabetically(obj);
};
export const TEST__buildGraphWithEntities = async (graphManagerState, entities, options) => {
    await graphManagerState.graphManager.initialize({
        env: 'test',
        tabSize: 2,
        clientConfig: {},
    });
    await graphManagerState.initializeSystem(options);
    await graphManagerState.graphManager.buildGraph(graphManagerState.graph, entities, graphManagerState.graphBuildState, options);
};
export const TEST__checkGraphHashUnchanged = async (graphManagerState, entities) => {
    const originalHashesIndex = await graphManagerState.graphManager.buildHashesIndex(entities);
    const currentGraphHashesIndex = new Map();
    await Promise.all(graphManagerState.graph.allOwnElements.map((element) => promisify(() => {
        currentGraphHashesIndex.set(element.path, element.hashCode);
    })));
    expect(Array.from(originalHashesIndex.entries()).filter((entry) => entry[0] !== SECTION_INDEX_ELEMENT_PATH)).toIncludeSameMembers(Array.from(currentGraphHashesIndex.entries()).filter((entry) => entry[0] !== SECTION_INDEX_ELEMENT_PATH));
};
export const TEST__checkBuildingElementsRoundtrip = async (entities, pluginManager) => {
    const graphManagerState = TEST__getTestGraphManagerState(pluginManager);
    await TEST__buildGraphWithEntities(graphManagerState, entities, {
        TEMPORARY__preserveSectionIndex: true,
    });
    const transformedEntities = graphManagerState.graph.allOwnElements.map((element) => graphManagerState.graphManager.elementToEntity(element));
    // ensure that transformed entities have all fields ordered alphabetically
    transformedEntities.forEach((entity) => TEST__ensureObjectFieldsAreSortedAlphabetically(entity.content));
    // check if the contents are the same (i.e. roundtrip test)
    expect(transformedEntities).toIncludeSameMembers(TEST__excludeSectionIndex(entities));
    await TEST__checkGraphHashUnchanged(graphManagerState, entities);
};
export const TEST__checkBuildingResolvedElements = async (entities, resolvedEntities) => {
    const graphManagerState = TEST__getTestGraphManagerState();
    await graphManagerState.graphManager.initialize({
        env: 'test',
        tabSize: 2,
        clientConfig: {},
    });
    await graphManagerState.initializeSystem();
    await graphManagerState.graphManager.buildGraph(graphManagerState.graph, entities, graphManagerState.graphBuildState);
    const transformedEntities = graphManagerState.graph.allOwnElements.map((element) => graphManagerState.graphManager.elementToEntity(element));
    // ensure that transformed entities have all fields ordered alphabetically
    transformedEntities.forEach((entity) => TEST__ensureObjectFieldsAreSortedAlphabetically(entity.content));
    // check if the contents are the same (i.e. roundtrip test)
    expect(transformedEntities).toIncludeSameMembers(TEST__excludeSectionIndex(resolvedEntities));
};
//# sourceMappingURL=GraphManagerTestUtils.js.map