/**
 * 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 { guaranteeNonNullable, isNonNullable, UnsupportedOperationError, } from '@finos/legend-shared';
import { AccessPointGroup, DataProductElementScope, DataProductEmbeddedImageIcon, DataProductLibraryIcon, DataProductLink, DataProductOperationalMetadata, Expertise, FunctionAccessPoint, LakehouseAccessPoint, ModelAccessPointGroup, UnknownAccessPoint, UnknownDataProductIcon, NativeModelAccess, PackageableElementSampleQuery, InLineSampleQuery, DataProductDiagram, NativeModelExecutionContext, AppDirOwner, } from '../../../../../../../../graph/metamodel/pure/dataProduct/DataProduct.js';
import { AppDirNode } from '../../../../../../../../graph/metamodel/pure/packageableElements/ingest/IngestDefinition.js';
import { V1_DataProductEmbeddedImageIcon, V1_DataProductLibraryIcon, V1_FunctionAccessPoint, V1_LakehouseAccessPoint, V1_ModelAccessPointGroup, V1_UnknownAccessPoint, V1_UnknownDataProductIcon, V1_PackageableElementSampleQuery, V1_InLineSampleQuery, V1_AppDirOwner, } from '../../../../model/packageableElements/dataProduct/V1_DataProduct.js';
import { V1_buildRawLambdaWithResolvedPaths } from './V1_ValueSpecificationPathResolver.js';
import { PackageableElementExplicitReference, } from '../../../../../../../../graph/metamodel/pure/packageableElements/PackageableElementReference.js';
import { Package } from '../../../../../../../../graph/metamodel/pure/packageableElements/domain/Package.js';
import { Class } from '../../../../../../../../graph/metamodel/pure/packageableElements/domain/Class.js';
import { Enumeration } from '../../../../../../../../graph/metamodel/pure/packageableElements/domain/Enumeration.js';
import { Association } from '../../../../../../../../graph/metamodel/pure/packageableElements/domain/Association.js';
import { generateFunctionPrettyName } from '../../../../../../../../graph/helpers/PureLanguageHelper.js';
import { DataProductAccessPointTest } from '../../../../../../../../graph/metamodel/pure/dataProduct/test/DataProductAccessPointTest.js';
import { DataProductTestSuite } from '../../../../../../../../graph/metamodel/pure/dataProduct/test/DataProductTestSuite.js';
import { V1_AccessPointTest } from '../../../../model/packageableElements/dataProduct/test/V1_AccessPointTest.js';
import { V1_buildDataResolver } from './V1_DataResolverBuilderHelper.js';
import { V1_buildTestAssertion } from './V1_TestBuilderHelper.js';
export const V1_buildDataProductLink = (link) => {
    return new DataProductLink(link.url, link.label);
};
export const V1_buildAccessPoint = (ap, context, owner) => {
    if (ap instanceof V1_LakehouseAccessPoint) {
        const lakeAccessPoint = new LakehouseAccessPoint(ap.id, ap.targetEnvironment, V1_buildRawLambdaWithResolvedPaths(ap.func.parameters, ap.func.body, context), owner);
        lakeAccessPoint.reproducible = ap.reproducible;
        lakeAccessPoint.classification = ap.classification;
        lakeAccessPoint.description = ap.description;
        lakeAccessPoint.title = ap.title;
        lakeAccessPoint.stereotypes = ap.stereotypes
            .map((stereotype) => context.resolveStereotype(stereotype))
            .filter(isNonNullable);
        return lakeAccessPoint;
    }
    else if (ap instanceof V1_FunctionAccessPoint) {
        const functionAccessPoint = new FunctionAccessPoint(ap.id, V1_buildRawLambdaWithResolvedPaths(ap.query.parameters, ap.query.body, context), owner);
        functionAccessPoint.description = ap.description;
        functionAccessPoint.title = ap.title;
        functionAccessPoint.stereotypes = ap.stereotypes
            .map((stereotype) => context.resolveStereotype(stereotype))
            .filter(isNonNullable);
        return functionAccessPoint;
    }
    else if (ap instanceof V1_UnknownAccessPoint) {
        const unknown = new UnknownAccessPoint(ap.id, owner);
        unknown.description = ap.description;
        unknown.title = ap.title;
        unknown.content = ap.content;
        return unknown;
    }
    throw new UnsupportedOperationError(`Unsupported data product access type ${ap}`);
};
export const V1_buildDataProductIcon = (icon) => {
    if (icon instanceof V1_DataProductLibraryIcon) {
        return new DataProductLibraryIcon(icon.libraryId, icon.iconId);
    }
    else if (icon instanceof V1_DataProductEmbeddedImageIcon) {
        return new DataProductEmbeddedImageIcon(icon.imageUrl);
    }
    else if (icon instanceof V1_UnknownDataProductIcon) {
        return new UnknownDataProductIcon(icon.content);
    }
    throw new UnsupportedOperationError(`Unsupported data product icon type ${icon}`);
};
export const V1_buildDataProductExpertise = (v1Expertise) => {
    const expertise = new Expertise();
    expertise.description = v1Expertise.description;
    expertise.expertIds = v1Expertise.expertIds;
    return expertise;
};
export const V1_buildDataProductOperationalMetadata = (operationalMetadata) => {
    const metamodelOperationalMetadata = new DataProductOperationalMetadata();
    metamodelOperationalMetadata.updateFrequency =
        operationalMetadata.updateFrequency;
    metamodelOperationalMetadata.coverageRegions =
        operationalMetadata.coverageRegions;
    return metamodelOperationalMetadata;
};
export const V1_buildAccessPointGroup = (elementGroup, context) => {
    if (elementGroup instanceof V1_ModelAccessPointGroup) {
        const group = new ModelAccessPointGroup();
        group.id = elementGroup.id;
        group.title = elementGroup.title;
        group.description = elementGroup.description;
        group.accessPoints = elementGroup.accessPoints.map((ep) => V1_buildAccessPoint(ep, context, group));
        group.stereotypes = elementGroup.stereotypes
            .map((stereotype) => context.resolveStereotype(stereotype))
            .filter(isNonNullable);
        group.mapping = PackageableElementExplicitReference.create(context.graph.getMapping(elementGroup.mapping.path));
        group.diagrams = elementGroup.diagrams.map((diagram) => {
            const metadatamodelDiagram = new DataProductDiagram();
            metadatamodelDiagram.diagram = context.graph.getElement(diagram.diagram.path);
            metadatamodelDiagram.title = diagram.title;
            metadatamodelDiagram.description = diagram.description;
            return metadatamodelDiagram;
        });
        if (elementGroup.featuredElements) {
            group.featuredElements = elementGroup.featuredElements.map((pointer) => {
                const elementReference = context.resolveElement(pointer.element.path, true);
                if (elementReference.value instanceof Package ||
                    elementReference.value instanceof Class ||
                    elementReference.value instanceof Enumeration ||
                    elementReference.value instanceof Association) {
                    const elementPointer = new DataProductElementScope();
                    elementPointer.element =
                        elementReference;
                    elementPointer.exclude = pointer.exclude;
                    return elementPointer;
                }
                throw new UnsupportedOperationError(`Can't find data product element (only allow packages, classes, enumerations, and associations) '${pointer.element.path}'`);
            });
        }
        return group;
    }
    else {
        const group = new AccessPointGroup();
        group.id = elementGroup.id;
        group.title = elementGroup.title;
        group.description = elementGroup.description;
        group.accessPoints = elementGroup.accessPoints.map((ep) => V1_buildAccessPoint(ep, context, group));
        group.stereotypes = elementGroup.stereotypes
            .map((stereotype) => context.resolveStereotype(stereotype))
            .filter(isNonNullable);
        return group;
    }
};
export const V1_buildNativeModelExecutionContext = (nativeModelExecutionContext, context, owner) => {
    const metamodelNativeModelExecutionContext = new NativeModelExecutionContext();
    metamodelNativeModelExecutionContext.key = nativeModelExecutionContext.key;
    metamodelNativeModelExecutionContext.mapping =
        PackageableElementExplicitReference.create(context.graph.getMapping(nativeModelExecutionContext.mapping.path));
    if (nativeModelExecutionContext.runtime) {
        metamodelNativeModelExecutionContext.runtime =
            PackageableElementExplicitReference.create(context.graph.getRuntime(nativeModelExecutionContext.runtime.path));
    }
    metamodelNativeModelExecutionContext.__owner = owner;
    return metamodelNativeModelExecutionContext;
};
export const V1_buildSampleQuery = (sampleQuery, defaultExecutionContext, context) => {
    if (sampleQuery instanceof V1_PackageableElementSampleQuery) {
        const metamodelSampleQuery = new PackageableElementSampleQuery();
        metamodelSampleQuery.id = sampleQuery.id;
        metamodelSampleQuery.title = sampleQuery.title;
        metamodelSampleQuery.description = sampleQuery.description;
        metamodelSampleQuery.executionContextKey =
            sampleQuery.executionContextKey ?? defaultExecutionContext;
        try {
            metamodelSampleQuery.query = context.resolveElement(sampleQuery.query.path, false);
        }
        catch {
            try {
                metamodelSampleQuery.query = PackageableElementExplicitReference.create(guaranteeNonNullable(context.graph.functions.find((fn) => generateFunctionPrettyName(fn, {
                    fullPath: true,
                    spacing: false,
                    notIncludeParamName: true,
                }) === sampleQuery.query.path.replaceAll(/\s*/gu, ''))));
            }
            catch {
                throw new UnsupportedOperationError(`Can't analyze data product executable with element in path: ${sampleQuery.query.path}`, sampleQuery);
            }
        }
        return metamodelSampleQuery;
    }
    else if (sampleQuery instanceof V1_InLineSampleQuery) {
        const metamodelSampleQuery = new InLineSampleQuery();
        metamodelSampleQuery.id = sampleQuery.id;
        metamodelSampleQuery.title = sampleQuery.title;
        metamodelSampleQuery.description = sampleQuery.description;
        metamodelSampleQuery.executionContextKey =
            sampleQuery.executionContextKey ?? defaultExecutionContext;
        metamodelSampleQuery.query = V1_buildRawLambdaWithResolvedPaths(sampleQuery.query.parameters, sampleQuery.query.body, context);
        return metamodelSampleQuery;
    }
    throw new UnsupportedOperationError(`Unsupported data product sample query type`);
};
export const V1_buildNativeModelAccess = (nativeModelAccess, context) => {
    const metamodelNativeModelAccess = new NativeModelAccess();
    metamodelNativeModelAccess.nativeModelExecutionContexts =
        nativeModelAccess.nativeModelExecutionContexts.map((executionContext) => V1_buildNativeModelExecutionContext(executionContext, context, metamodelNativeModelAccess));
    metamodelNativeModelAccess.defaultExecutionContext = guaranteeNonNullable(metamodelNativeModelAccess.nativeModelExecutionContexts.find((e) => e.key === nativeModelAccess.defaultExecutionContext), `Default execution context ${nativeModelAccess.defaultExecutionContext} not found among native model execution contexts`);
    if (nativeModelAccess.sampleQueries) {
        metamodelNativeModelAccess.sampleQueries =
            nativeModelAccess.sampleQueries.map((sampleQuery) => V1_buildSampleQuery(sampleQuery, nativeModelAccess.defaultExecutionContext, context));
    }
    if (!nativeModelAccess.diagrams) {
        metamodelNativeModelAccess.diagrams = [];
    }
    else {
        metamodelNativeModelAccess.diagrams = nativeModelAccess.diagrams.map((diagram) => {
            const metadatamodelDiagram = new DataProductDiagram();
            metadatamodelDiagram.diagram = context.graph.getElement(diagram.diagram.path);
            metadatamodelDiagram.title = diagram.title;
            metadatamodelDiagram.description = diagram.description;
            return metadatamodelDiagram;
        });
    }
    if (nativeModelAccess.featuredElements) {
        metamodelNativeModelAccess.featuredElements =
            nativeModelAccess.featuredElements.map((pointer) => {
                const elementReference = context.resolveElement(pointer.element.path, true);
                if (elementReference.value instanceof Package ||
                    elementReference.value instanceof Class ||
                    elementReference.value instanceof Enumeration ||
                    elementReference.value instanceof Association) {
                    const elementPointer = new DataProductElementScope();
                    elementPointer.element =
                        elementReference;
                    elementPointer.exclude = pointer.exclude;
                    return elementPointer;
                }
                throw new UnsupportedOperationError(`Can't find data product element (only allow packages, classes, enumerations, and associations) '${pointer.element.path}'`);
            });
    }
    return metamodelNativeModelAccess;
};
export const V1_buildDataProductOwner = (v1Owner) => {
    if (v1Owner instanceof V1_AppDirOwner) {
        const owner = new AppDirOwner();
        if (v1Owner.production) {
            const production = new AppDirNode();
            production.appDirId = v1Owner.production.appDirId;
            production.level = v1Owner.production.level;
            owner.production = production;
        }
        if (v1Owner.prodParallel) {
            const prodParallel = new AppDirNode();
            prodParallel.appDirId = v1Owner.prodParallel.appDirId;
            prodParallel.level = v1Owner.prodParallel.level;
            owner.prodParallel = prodParallel;
        }
        return owner;
    }
    throw new UnsupportedOperationError(`Unsupported data product owner type`, v1Owner);
};
const V1_buildDataProductAccessPointTest = (element, parentSuite, context) => {
    const accessPointTest = new DataProductAccessPointTest();
    accessPointTest.id = element.id;
    accessPointTest.__parent = parentSuite;
    accessPointTest.doc = element.doc;
    accessPointTest.accessPointId = element.accessPointId;
    accessPointTest.assertions = element.assertions.map((assertion) => V1_buildTestAssertion(assertion, accessPointTest, context));
    return accessPointTest;
};
export const V1_buildDataProductTestSuite = (element, context) => {
    const testSuite = new DataProductTestSuite();
    testSuite.id = element.id;
    testSuite.doc = element.doc;
    if (element.testData?.length) {
        testSuite.testData = element.testData.map((dataResolver) => V1_buildDataResolver(dataResolver, context));
    }
    testSuite.tests = element.tests.map((test) => {
        if (test instanceof V1_AccessPointTest) {
            return V1_buildDataProductAccessPointTest(test, testSuite, context);
        }
        throw new UnsupportedOperationError('Unable to build data product test: Unsupported data product test type');
    });
    return testSuite;
};
//# sourceMappingURL=V1_DataProductBuilder.js.map