/**
 * 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 { UnsupportedOperationError, assertTrue, isNonNullable, assertErrorThrown, guaranteeNonNullable, LogEvent, addUniqueEntry, } from '@finos/legend-shared';
import { CORE_PURE_PATH } from '../../../../../../../graph/MetaModelConst.js';
import { Class } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/Class.js';
import { V1_buildFullPath, } from './V1_GraphBuilderContext.js';
import { V1_ClassMappingFirstPassBuilder } from './V1_ClassMappingFirstPassBuilder.js';
import { V1_buildAssociationProperty, V1_buildDerivedProperty, V1_buildProperty, V1_buildTaggedValue, } from './helpers/V1_DomainBuilderHelper.js';
import { V1_buildDatabaseSchemaViewsFirstPass } from './helpers/V1_DatabaseBuilderHelper.js';
import { GraphBuilderError } from '../../../../../../../graph-manager/GraphManagerUtils.js';
import { V1_TEMPORARY__buildMilestoningClass } from './helpers/V1_MilestoneBuilderHelper.js';
export class V1_ElementThirdPassBuilder {
    context;
    constructor(context) {
        this.context = context;
    }
    visit_PackageableElement(element) {
        this.context.extensions
            .getExtraBuilderOrThrow(element)
            .runThirdPass(element, this.context);
    }
    visit_INTERNAL__UnknownElement(element) {
        throw new UnsupportedOperationError();
    }
    visit_INTERNAL__UnknownPackageableElement(element) {
        throw new UnsupportedOperationError();
    }
    visit_IngestDefinition(element) {
        throw new UnsupportedOperationError();
    }
    visit_INTERNAL__UnknownFunctionActivator(element) {
        throw new UnsupportedOperationError();
    }
    visit_INTERNAL__UnknownStore(element) {
        return;
    }
    visit_Profile(element) {
        throw new UnsupportedOperationError();
    }
    visit_Enumeration(element) {
        throw new UnsupportedOperationError();
    }
    visit_Measure(element) {
        throw new UnsupportedOperationError();
    }
    visit_SnowflakeApp(element) {
        throw new UnsupportedOperationError();
    }
    visit_SnowflakeM2MUdf(element) {
        throw new UnsupportedOperationError();
    }
    visit_MemSQLFunction(element) {
        throw new UnsupportedOperationError();
    }
    visit_HostedService(element) {
        throw new UnsupportedOperationError();
    }
    visit_ExecutionEnvironmentInstance(element) {
        throw new UnsupportedOperationError();
    }
    visit_Class(element) {
        const _class = this.context.currentSubGraph.getOwnClass(V1_buildFullPath(element.package, element.name));
        element.superTypes.forEach((pointer) => {
            const type = pointer.path;
            // supertype `Any` will not be processed
            if (type !== CORE_PURE_PATH.ANY) {
                try {
                    const genericTypeReference = this.context.resolveGenericType(type);
                    addUniqueEntry(_class.generalizations, genericTypeReference);
                    if (genericTypeReference.ownerReference.value instanceof Class) {
                        addUniqueEntry(genericTypeReference.ownerReference.value._subclasses, _class);
                    }
                }
                catch (error) {
                    assertErrorThrown(error);
                    // NOTE: reconsider this as we might need to get elements from `system` and `platform` as well
                    throw new GraphBuilderError(`Can't find supertype '${type}' of class '${V1_buildFullPath(element.package, element.name)}': ${error.message}`);
                }
            }
        });
        const uniqueProperties = new Set();
        element.properties.forEach((property) => {
            if (uniqueProperties.has(property.name)) {
                const message = `Found duplicated property '${property.name}' in class '${_class.path}'`;
                /**
                 * In strict-mode, graph builder will consider this as an error
                 * See https://github.com/finos/legend-studio/issues/941
                 *
                 * @discrepancy graph-building
                 */
                if (this.context.options?.strict) {
                    throw new GraphBuilderError(message);
                }
                this.context.logService.warn(LogEvent.create(message));
            }
            _class.properties.push(V1_buildProperty(property, this.context, _class));
            uniqueProperties.add(property.name);
        });
        V1_TEMPORARY__buildMilestoningClass(_class, this.context.graph);
    }
    visit_Association(element) {
        const association = this.context.currentSubGraph.getOwnAssociation(V1_buildFullPath(element.package, element.name));
        assertTrue(element.properties.length === 2, 'Association must have exactly 2 properties');
        const first = guaranteeNonNullable(element.properties[0]);
        const second = guaranteeNonNullable(element.properties[1]);
        if (first.name === second.name) {
            const message = `Found duplicated property '${element.properties[0]?.name}' in association '${element.path}'`;
            /**
             * In strict-mode, graph builder will consider this as an error
             * See https://github.com/finos/legend-studio/issues/941
             *
             * @discrepancy graph-building
             */
            if (this.context.options?.strict) {
                throw new GraphBuilderError(message);
            }
            this.context.logService.warn(LogEvent.create(message));
        }
        association.properties = [
            V1_buildAssociationProperty(first, second, this.context, association),
            V1_buildAssociationProperty(second, first, this.context, association),
        ];
        association.stereotypes = element.stereotypes
            .map((stereotype) => this.context.resolveStereotype(stereotype))
            .filter(isNonNullable);
        association.taggedValues = element.taggedValues
            .map((taggedValue) => V1_buildTaggedValue(taggedValue, this.context))
            .filter(isNonNullable);
        association.derivedProperties = element.derivedProperties.map((derivedProperty) => V1_buildDerivedProperty(derivedProperty, this.context, association));
    }
    visit_ConcreteFunctionDefinition(element) {
        throw new UnsupportedOperationError();
    }
    visit_FlatData(element) {
        return;
    }
    visit_Database(element) {
        const database = this.context.currentSubGraph.getOwnDatabase(V1_buildFullPath(element.package, element.name));
        element.schemas.forEach((schema) => V1_buildDatabaseSchemaViewsFirstPass(schema, database, this.context));
    }
    visit_Mapping(element) {
        const mapping = this.context.currentSubGraph.getOwnMapping(V1_buildFullPath(element.package, element.name));
        mapping.classMappings = element.classMappings.map((classMapping) => classMapping.accept_ClassMappingVisitor(new V1_ClassMappingFirstPassBuilder(this.context, mapping)));
    }
    visit_Service(element) {
        throw new UnsupportedOperationError();
    }
    visit_FileGeneration(element) {
        throw new UnsupportedOperationError();
    }
    visit_GenerationSpecification(element) {
        throw new UnsupportedOperationError();
    }
    visit_SectionIndex(element) {
        throw new UnsupportedOperationError();
    }
    visit_PackageableRuntime(element) {
        throw new UnsupportedOperationError();
    }
    visit_PackageableConnection(element) {
        throw new UnsupportedOperationError();
    }
    visit_DataElement(element) {
        throw new UnsupportedOperationError();
    }
    visit_DataProduct(element) {
        throw new UnsupportedOperationError();
    }
}
//# sourceMappingURL=V1_ElementThirdPassBuilder.js.map