/**
 * 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 { assertNonEmptyString, isNonNullable } from '@finos/legend-shared';
import { Profile } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/Profile.js';
import { Enumeration } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/Enumeration.js';
import { Measure } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/Measure.js';
import { Class } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/Class.js';
import { Association } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/Association.js';
import { ConcreteFunctionDefinition } from '../../../../../../../graph/metamodel/pure/packageableElements/function/ConcreteFunctionDefinition.js';
import { FlatData } from '../../../../../../../graph/metamodel/pure/packageableElements/store/flatData/model/FlatData.js';
import { Database } from '../../../../../../../graph/metamodel/pure/packageableElements/store/relational/model/Database.js';
import { Mapping } from '../../../../../../../graph/metamodel/pure/packageableElements/mapping/Mapping.js';
import { Service } from '../../../../../../../graph/metamodel/pure/packageableElements/service/Service.js';
import { FileGenerationSpecification } from '../../../../../../../graph/metamodel/pure/packageableElements/fileGeneration/FileGenerationSpecification.js';
import { PackageableRuntime } from '../../../../../../../graph/metamodel/pure/packageableElements/runtime/PackageableRuntime.js';
import { PackageableConnection } from '../../../../../../../graph/metamodel/pure/packageableElements/connection/PackageableConnection.js';
import { GenerationSpecification } from '../../../../../../../graph/metamodel/pure/packageableElements/generationSpecification/GenerationSpecification.js';
import { SectionIndex } from '../../../../../../../graph/metamodel/pure/packageableElements/section/SectionIndex.js';
import { PackageableElementImplicitReference } from '../../../../../../../graph/metamodel/pure/packageableElements/PackageableElementReference.js';
import { V1_buildFullPath, } from './V1_GraphBuilderContext.js';
import { addElementToPackage, getOrCreateGraphPackage, } from '../../../../../../../graph/helpers/DomainHelper.js';
import { V1_checkDuplicatedElement } from './V1_ElementBuilder.js';
import { DataElement } from '../../../../../../../graph/metamodel/pure/packageableElements/data/DataElement.js';
import { V1_buildFunctionSignature } from '../../../helpers/V1_DomainHelper.js';
import { Multiplicity } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/Multiplicity.js';
import { PrimitiveType } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/PrimitiveType.js';
import { ExecutionEnvironmentInstance } from '../../../../../../../graph/metamodel/pure/packageableElements/service/ExecutionEnvironmentInstance.js';
import { INTERNAL__UnknownPackageableElement } from '../../../../../../../graph/metamodel/pure/packageableElements/INTERNAL__UnknownPackageableElement.js';
import { INTERNAL__UnknownFunctionActivator } from '../../../../../../../graph/metamodel/pure/packageableElements/function/INTERNAL__UnknownFunctionActivator.js';
import { INTERNAL__UnknownStore } from '../../../../../../../graph/metamodel/pure/packageableElements/store/INTERNAL__UnknownStore.js';
import { SnowflakeApp } from '../../../../../../../graph/metamodel/pure/packageableElements/function/SnowflakeApp.js';
import { SnowflakeM2MUdf } from '../../../../../../../graph/metamodel/pure/packageableElements/function/SnowflakeM2MUdf.js';
import { INTERNAL__UnknownElement } from '../../../../../../../graph/metamodel/pure/packageableElements/INTERNAL__UnknownElement.js';
import { HostedService } from '../../../../../../../graph/metamodel/pure/packageableElements/function/HostedService.js';
import { V1_buildFunctionActivatorActions } from './helpers/V1_LegendLambdaHelper.js';
import { GenericTypeImplicitReference } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/GenericTypeReference.js';
import { GenericType } from '../../../../../../../graph/metamodel/pure/packageableElements/domain/GenericType.js';
import { DataProduct } from '../../../../../../../graph/metamodel/pure/dataProduct/DataProduct.js';
import { AppDirNode, IngestDefinition, } from '../../../../../../../graph/metamodel/pure/packageableElements/ingest/IngestDefinition.js';
import { MemSQLFunction } from '../../../../../../../graph/metamodel/pure/packageableElements/function/MemSQLFunction.js';
import { RawLambda } from '../../../../../../../graph/metamodel/pure/rawValueSpecification/RawLambda.js';
export class V1_ElementFirstPassBuilder {
    context;
    packageCache;
    elementPathCache;
    constructor(context, packageCache, elementPathCache) {
        this.context = context;
        this.packageCache = packageCache;
        this.elementPathCache = elementPathCache;
    }
    visit_PackageableElement(element) {
        return this.context.extensions
            .getExtraBuilderOrThrow(element)
            .runFirstPass(element, this.context, this.packageCache, this.elementPathCache);
    }
    visit_INTERNAL__UnknownElement(element) {
        assertNonEmptyString(element.package, `Element 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Element 'name' field is missing or empty`);
        const metamodel = new INTERNAL__UnknownElement(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.INTERNAL__setOwnUnknown(path, metamodel);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), metamodel);
        metamodel.content = element.content;
        metamodel.classifierPath = element.classifierPath;
        return metamodel;
    }
    visit_INTERNAL__UnknownPackageableElement(element) {
        assertNonEmptyString(element.package, `Element 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Element 'name' field is missing or empty`);
        const metamodel = new INTERNAL__UnknownPackageableElement(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.INTERNAL__setOwnUnknownElement(path, metamodel);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), metamodel);
        metamodel.content = element.content;
        return metamodel;
    }
    visit_IngestDefinition(element) {
        assertNonEmptyString(element.package, `Element 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Element 'name' field is missing or empty`);
        const metamodel = new IngestDefinition(element.name);
        const appDir = element.appDirDeployment;
        if (appDir) {
            const metamodelApp = new AppDirNode();
            metamodelApp.appDirId = appDir.appDirId;
            metamodelApp.level = appDir.level;
            metamodel.appDirDeployment = metamodelApp;
        }
        const rawContent = element.content;
        const dataSets = rawContent.datasets ?? [];
        if (dataSets.length > 0) {
            const matViewDataSets = dataSets
                .filter((dataset) => dataset.source?._type === 'FunctionSource' &&
                dataset.source.function?._type === 'lambda')
                .map((dataset) => {
                const source = dataset.source;
                const functionData = source?.function;
                if (!source || !functionData) {
                    return undefined;
                }
                const matViewDataSet = {
                    name: dataset.name,
                    source: {
                        function: new RawLambda(functionData.parameters ?? [], functionData.body),
                    },
                };
                return matViewDataSet;
            })
                .filter(isNonNullable);
            metamodel.TEMPORARY_MATVIEW_FUNCTION_DATA_SETS = matViewDataSets;
        }
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.INTERNAL__setOwnUnknownElement(path, metamodel);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), metamodel);
        metamodel.content = element.content;
        return metamodel;
    }
    visit_SnowflakeApp(element) {
        assertNonEmptyString(element.package, `Function activator 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Function activator 'name' field is missing or empty`);
        const metamodel = new SnowflakeApp(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.setOwnFunctionActivator(path, metamodel);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), metamodel);
        metamodel.applicationName = element.applicationName;
        metamodel.description = element.description;
        if (element.usageRole) {
            metamodel.usageRole = element.usageRole;
        }
        if (element.deploymentSchema) {
            metamodel.deploymentSchema = element.deploymentSchema;
        }
        if (element.permissionScheme) {
            metamodel.permissionScheme = element.permissionScheme;
        }
        V1_buildFunctionActivatorActions(element, metamodel, this.context);
        return metamodel;
    }
    visit_MemSQLFunction(element) {
        assertNonEmptyString(element.package, `Function activator 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Function activator 'name' field is missing or empty`);
        const metamodel = new MemSQLFunction(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.setOwnFunctionActivator(path, metamodel);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), metamodel);
        metamodel.functionName = element.functionName;
        metamodel.description = element.description;
        V1_buildFunctionActivatorActions(element, metamodel, this.context);
        return metamodel;
    }
    visit_SnowflakeM2MUdf(element) {
        assertNonEmptyString(element.package, `Function activator 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Function activator 'name' field is missing or empty`);
        const metamodel = new SnowflakeM2MUdf(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.setOwnFunctionActivator(path, metamodel);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), metamodel);
        metamodel.udfName = element.udfName;
        metamodel.description = element.description;
        if (element.deploymentSchema) {
            metamodel.deploymentSchema = element.deploymentSchema;
        }
        metamodel.deploymentStage = element.deploymentStage;
        V1_buildFunctionActivatorActions(element, metamodel, this.context);
        return metamodel;
    }
    visit_HostedService(element) {
        assertNonEmptyString(element.package, `Rest Service 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Rest Service 'name' field is missing or empty`);
        const metamodel = new HostedService(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.setOwnFunctionActivator(path, metamodel);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), metamodel);
        metamodel.documentation = element.documentation;
        metamodel.pattern = element.pattern;
        metamodel.autoActivateUpdates = element.autoActivateUpdates;
        metamodel.storeModel = element.storeModel;
        metamodel.generateLineage = element.generateLineage;
        metamodel.actions = element.actions;
        V1_buildFunctionActivatorActions(element, metamodel, this.context);
        return metamodel;
    }
    visit_INTERNAL__UnknownFunctionActivator(element) {
        assertNonEmptyString(element.package, `Function activator 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Function activator 'name' field is missing or empty`);
        const metamodel = new INTERNAL__UnknownFunctionActivator(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.setOwnFunctionActivator(path, metamodel);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), metamodel);
        metamodel.content = element.content;
        return metamodel;
    }
    visit_INTERNAL__UnknownStore(element) {
        assertNonEmptyString(element.package, `Store 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Store 'name' field is missing or empty`);
        const metamodel = new INTERNAL__UnknownStore(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.setOwnStore(path, metamodel);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), metamodel);
        metamodel.content = element.content;
        return metamodel;
    }
    visit_SectionIndex(element) {
        assertNonEmptyString(element.package, `Section index 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Section index 'name' field is missing or empty`);
        const sectionIndex = new SectionIndex(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        this.context.currentSubGraph.setOwnSectionIndex(path, sectionIndex);
        return sectionIndex;
    }
    visit_Profile(element) {
        assertNonEmptyString(element.package, `Profile 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Profile 'name' field is missing or empty`);
        const profile = new Profile(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), profile);
        this.context.currentSubGraph.setOwnProfile(path, profile);
        return profile;
    }
    visit_Enumeration(element) {
        assertNonEmptyString(element.package, `Enumeration 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Enumeration 'name' field is missing or empty`);
        const pureEnumeration = new Enumeration(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), pureEnumeration);
        this.context.currentSubGraph.setOwnType(path, pureEnumeration);
        return pureEnumeration;
    }
    visit_Measure(element) {
        assertNonEmptyString(element.package, `Measure 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Measure 'name' field is missing or empty`);
        const pureMeasure = new Measure(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), pureMeasure);
        this.context.currentSubGraph.setOwnType(path, pureMeasure);
        return pureMeasure;
    }
    visit_Class(element) {
        assertNonEmptyString(element.package, `Class 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Class 'name' field is missing or empty`);
        const _class = new Class(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), _class);
        this.context.currentSubGraph.setOwnType(path, _class);
        return _class;
    }
    visit_Association(element) {
        assertNonEmptyString(element.package, `Association 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Association 'name' field is missing or empty`);
        const association = new Association(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), association);
        this.context.currentSubGraph.setOwnAssociation(path, association);
        return association;
    }
    visit_ConcreteFunctionDefinition(element) {
        assertNonEmptyString(element.package, `Function 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Function 'name' field is missing or empty`);
        const name = V1_buildFunctionSignature(element);
        const func = new ConcreteFunctionDefinition(name, 
        // This is just a stub to fill in when we first create the function
        GenericTypeImplicitReference.create(PackageableElementImplicitReference.create(PrimitiveType.STRING, ''), new GenericType(PrimitiveType.STRING)), Multiplicity.ZERO_MANY);
        const path = V1_buildFullPath(element.package, name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), func);
        this.context.currentSubGraph.setOwnFunction(path, func);
        return func;
    }
    visit_FlatData(element) {
        assertNonEmptyString(element.package, `Flat-data store 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Flat data store 'name' field is missing or empty`);
        const flatData = new FlatData(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), flatData);
        this.context.currentSubGraph.setOwnStore(path, flatData);
        return flatData;
    }
    visit_Database(element) {
        assertNonEmptyString(element.package, `Database store 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Database store 'name' field is missing or empty`);
        const database = new Database(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), database);
        this.context.currentSubGraph.setOwnStore(path, database);
        return database;
    }
    visit_Mapping(element) {
        assertNonEmptyString(element.package, `Mapping 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Mapping 'name' field is missing or empty`);
        const pureMapping = new Mapping(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), pureMapping);
        this.context.currentSubGraph.setOwnMapping(path, pureMapping);
        return pureMapping;
    }
    visit_Service(element) {
        assertNonEmptyString(element.package, `Service 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Service 'name' field is missing or empty`);
        const service = new Service(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), service);
        this.context.currentSubGraph.setOwnService(path, service);
        return service;
    }
    visit_FileGeneration(element) {
        assertNonEmptyString(element.package, 'File generation element package is missing');
        assertNonEmptyString(element.name, 'File generation element name is missing');
        const fileGeneration = new FileGenerationSpecification(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), fileGeneration);
        this.context.currentSubGraph.setOwnFileGeneration(path, fileGeneration);
        return fileGeneration;
    }
    // TODO: Add support for generation specification
    visit_GenerationSpecification(element) {
        assertNonEmptyString(element.package, 'Generation tree element package is missing');
        assertNonEmptyString(element.name, 'Generation tree element name is missing');
        const generationSpec = new GenerationSpecification(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), generationSpec);
        this.context.currentSubGraph.setOwnGenerationSpecification(path, generationSpec);
        return generationSpec;
    }
    visit_PackageableRuntime(element) {
        assertNonEmptyString(element.package, `Runtime 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Runtime 'name' field is missing or empty`);
        const runtime = new PackageableRuntime(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), runtime);
        this.context.currentSubGraph.setOwnRuntime(path, runtime);
        return runtime;
    }
    visit_PackageableConnection(element) {
        assertNonEmptyString(element.package, `Connection 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Connection 'name' field is missing or empty`);
        const connection = new PackageableConnection(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), connection);
        this.context.currentSubGraph.setOwnConnection(path, connection);
        return connection;
    }
    visit_DataElement(element) {
        assertNonEmptyString(element.package, `Data element 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Data element 'name' field is missing or empty`);
        const dataElement = new DataElement(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), dataElement);
        this.context.currentSubGraph.setOwnDataElement(path, dataElement);
        return dataElement;
    }
    visit_ExecutionEnvironmentInstance(element) {
        assertNonEmptyString(element.package, `Execution Environment 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Execution Environment 'name' field is missing or empty`);
        const exEnvir = new ExecutionEnvironmentInstance(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), exEnvir);
        this.context.currentSubGraph.setOwnExecutionEnvironment(path, exEnvir);
        return exEnvir;
    }
    visit_DataProduct(element) {
        assertNonEmptyString(element.package, `Data Product 'package' field is missing or empty`);
        assertNonEmptyString(element.name, `Data Product 'name' field is missing or empty`);
        const product = new DataProduct(element.name);
        const path = V1_buildFullPath(element.package, element.name);
        V1_checkDuplicatedElement(path, this.context, this.elementPathCache);
        addElementToPackage(getOrCreateGraphPackage(this.context.currentSubGraph, element.package, this.packageCache), product);
        this.context.currentSubGraph.setOwnDataProduct(path, product);
        return product;
    }
}
//# sourceMappingURL=V1_ElementFirstPassBuilder.js.map