/**
 * 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, assertNonEmptyString, guaranteeNonEmptyString, guaranteeNonNullable, } from '@finos/legend-shared';
import { LightQuery, Query, QueryDataSpaceExecutionContext, QueryExplicitExecutionContext, QueryParameterValue, QueryStereotype, QueryTaggedValue, QueryExplicitExecutionContextInfo, QueryDataSpaceExecutionContextInfo, QueryDataProductExecutionContext, } from '../../../../../graph-manager/action/query/Query.js';
import { V1_Query, V1_QueryParameterValue, V1_QueryExplicitExecutionContext, V1_QueryDataSpaceExecutionContext, V1_QueryDataProductExecutionContext, } from './query/V1_Query.js';
import { DEPRECATED__ServiceTestResult } from '../../../../../graph-manager/action/service/DEPRECATED__ServiceTestResult.js';
import { ServiceRegistrationSuccess } from '../../../../../graph-manager/action/service/ServiceRegistrationResult.js';
import { GenerationOutput } from '../../../../../graph-manager/action/generation/GenerationOutput.js';
import { GenerationConfigurationDescription, GenerationMode, GenerationProperty, GenerationPropertyItem, getGenerationPropertyItemType, } from '../../../../../graph-manager/action/generation/GenerationConfigurationDescription.js';
import { CompilationError, EngineError, ParserError, } from '../../../../../graph-manager/action/EngineError.js';
import { SourceInformation } from '../../../../../graph-manager/action/SourceInformation.js';
import { ExecutionError } from '../../../../../graph-manager/action/ExecutionError.js';
import { V1_QueryProjectCoordinates, V1_QuerySearchSpecification, V1_QuerySearchTermSpecification, } from './query/V1_QuerySearchSpecification.js';
import { V1_TaggedValue } from '../model/packageableElements/domain/V1_TaggedValue.js';
import { V1_TagPtr } from '../model/packageableElements/domain/V1_TagPtr.js';
import { V1_StereotypePtr } from '../model/packageableElements/domain/V1_StereotypePtr.js';
import { ExternalFormatDescription } from '../../../../../graph-manager/action/externalFormat/ExternalFormatDescription.js';
import { QUERY_PROFILE_PATH } from '../../../../../graph/MetaModelConst.js';
import { isValidFullPath } from '../../../../../graph/MetaModelUtils.js';
import { PackageableElementExplicitReference } from '../../../../../graph/metamodel/pure/packageableElements/PackageableElementReference.js';
import { FunctionAnalysisInfo, FunctionAnalysisParameterInfo, } from '../../../../../graph/helpers/FunctionAnalysis.js';
import { V1_buildFunctionSignatureSuffix, V1_buildFunctionPrettyName, V1_getGenericTypeFullPath, } from '../helpers/V1_DomainHelper.js';
export const V1_buildLightQuery = (protocol, currentUserId) => {
    const metamodel = new LightQuery();
    metamodel.name = guaranteeNonNullable(protocol.name, `Query 'name' field is missing`);
    metamodel.id = guaranteeNonNullable(protocol.id, `Query 'id' field is missing`);
    metamodel.versionId = guaranteeNonNullable(protocol.versionId, `Query 'versionId' field is missing`);
    metamodel.originalVersionId = protocol.originalVersionId;
    metamodel.groupId = guaranteeNonNullable(protocol.groupId, `Query 'groupId' field is missing`);
    metamodel.artifactId = guaranteeNonNullable(protocol.artifactId, `Query 'artifactId' field is missing`);
    metamodel.owner = protocol.owner;
    metamodel.description = protocol.description;
    metamodel.lastUpdatedAt = protocol.lastUpdatedAt;
    metamodel.createdAt = protocol.createdAt;
    metamodel.lastOpenAt = protocol.lastOpenAt;
    metamodel.isCurrentUserQuery =
        currentUserId !== undefined && protocol.owner === currentUserId;
    return metamodel;
};
const getDataSpaceQueryInfo = (query) => {
    const dataSpaceTaggedValue = query.taggedValues?.find((taggedValue) => taggedValue.tag.profile === QUERY_PROFILE_PATH &&
        // move to dsl-dataSpace
        taggedValue.tag.value === 'dataSpace' &&
        isValidFullPath(taggedValue.value));
    return dataSpaceTaggedValue?.value;
};
export const V1_buildExecutionContext = (protocolQuery, graph, metamodel) => {
    const protocolExecContext = protocolQuery.executionContext;
    const dataspace = getDataSpaceQueryInfo(protocolQuery);
    if (dataspace) {
        const exec = new QueryDataSpaceExecutionContext();
        exec.dataSpacePath = dataspace;
        return exec;
    }
    else if (protocolQuery.mapping && protocolQuery.runtime) {
        const exec = new QueryExplicitExecutionContext();
        exec.mapping = PackageableElementExplicitReference.create(graph.getMapping(guaranteeNonNullable(protocolQuery.mapping, `Query 'mapping' field is missing`)));
        exec.runtime = PackageableElementExplicitReference.create(graph.getRuntime(guaranteeNonNullable(protocolQuery.runtime, `Query 'runtime' field is missing`)));
        metamodel.mapping = exec.mapping;
        metamodel.runtime = exec.runtime;
        return exec;
    }
    else if (protocolExecContext instanceof V1_QueryExplicitExecutionContext) {
        const exec = new QueryExplicitExecutionContext();
        exec.mapping = PackageableElementExplicitReference.create(graph.getMapping(guaranteeNonNullable(protocolExecContext.mapping, `Query 'mapping' field is missing`)));
        exec.runtime = PackageableElementExplicitReference.create(graph.getRuntime(guaranteeNonNullable(protocolExecContext.runtime, `Query 'runtime' field is missing`)));
        return exec;
    }
    else if (protocolExecContext instanceof V1_QueryDataSpaceExecutionContext) {
        const exec = new QueryDataSpaceExecutionContext();
        exec.dataSpacePath = protocolExecContext.dataSpacePath;
        exec.executionKey = protocolExecContext.executionKey;
        return exec;
    }
    throw new UnsupportedOperationError('Unsupported query execution context');
};
export const V1_buildExecutionContextInfo = (protocol) => {
    const v1_execContext = protocol.executionContext;
    const dataspace = getDataSpaceQueryInfo(protocol);
    if (dataspace) {
        const exec = new QueryDataSpaceExecutionContextInfo();
        exec.dataSpacePath = dataspace;
        if (v1_execContext instanceof V1_QueryDataSpaceExecutionContext) {
            exec.executionKey = v1_execContext.executionKey;
        }
        return exec;
    }
    else if (protocol.mapping && protocol.runtime) {
        const exec = new QueryExplicitExecutionContextInfo();
        exec.mapping = protocol.mapping;
        exec.runtime = protocol.runtime;
        return exec;
    }
    else if (v1_execContext instanceof V1_QueryExplicitExecutionContext) {
        const exec = new QueryExplicitExecutionContextInfo();
        exec.mapping = v1_execContext.mapping;
        exec.runtime = v1_execContext.runtime;
        return exec;
    }
    else if (v1_execContext instanceof V1_QueryDataSpaceExecutionContext) {
        const exec = new QueryDataSpaceExecutionContextInfo();
        exec.dataSpacePath = v1_execContext.dataSpacePath;
        exec.executionKey = v1_execContext.executionKey;
        return exec;
    }
    throw new UnsupportedOperationError('Unsupported query execution context');
};
export const V1_buildQuery = (protocol, graph, currentUserId) => {
    const metamodel = new Query();
    metamodel.name = guaranteeNonNullable(protocol.name, `Query 'name' field is missing`);
    metamodel.id = guaranteeNonNullable(protocol.id, `Query 'id' field is missing`);
    metamodel.description = protocol.description;
    metamodel.versionId = guaranteeNonNullable(protocol.versionId, `Query 'versionId' field is missing`);
    metamodel.groupId = guaranteeNonNullable(protocol.groupId, `Query 'groupId' field is missing`);
    metamodel.artifactId = guaranteeNonNullable(protocol.artifactId, `Query 'artifactId' field is missing`);
    metamodel.executionContext = V1_buildExecutionContext(protocol, graph, metamodel);
    metamodel.content = guaranteeNonNullable(protocol.content, `Query 'content' field is missing`);
    metamodel.owner = protocol.owner;
    metamodel.isCurrentUserQuery =
        currentUserId !== undefined && protocol.owner === currentUserId;
    // NOTE: we don't properly process tagged values and stereotypes for query
    // because these profiles/tags/stereotypes can come from external systems.
    metamodel.taggedValues = protocol.taggedValues?.map((taggedValueProtocol) => {
        const taggedValue = new QueryTaggedValue();
        taggedValue.profile = guaranteeNonEmptyString(taggedValueProtocol.tag.profile, `Tagged value 'tag.profile' field is missing or empty`);
        taggedValue.tag = guaranteeNonEmptyString(taggedValueProtocol.tag.value, `Tagged value 'tag.value' field is missing or empty`);
        taggedValue.value = guaranteeNonEmptyString(taggedValueProtocol.value, `Tagged value 'value' field is missing or empty`);
        return taggedValue;
    });
    metamodel.stereotypes = protocol.stereotypes?.map((stereotypeProtocol) => {
        const stereotype = new QueryStereotype();
        stereotype.profile = guaranteeNonEmptyString(stereotypeProtocol.profile, `Stereotype pointer 'profile' field is missing or empty`);
        stereotype.stereotype = guaranteeNonEmptyString(stereotypeProtocol.value, `Stereotype pointer 'value' field is missing or empty`);
        return stereotype;
    });
    metamodel.defaultParameterValues = protocol.defaultParameterValues?.map((v) => {
        const paramValue = new QueryParameterValue();
        paramValue.name = guaranteeNonEmptyString(v.name, `Query Parameter 'name' field is missing or empty`);
        paramValue.content = guaranteeNonEmptyString(v.content, `Query Parameter ${v.name} 'content' field is missing or empty`);
        return paramValue;
    });
    if (protocol.gridConfig) {
        metamodel.gridConfig = protocol.gridConfig;
    }
    return metamodel;
};
export const V1_transformQueryExecutionContext = (execContext) => {
    if (execContext instanceof QueryExplicitExecutionContext) {
        const protocol = new V1_QueryExplicitExecutionContext();
        protocol.mapping = execContext.mapping.valueForSerialization ?? '';
        protocol.runtime = execContext.runtime.valueForSerialization ?? '';
        return protocol;
    }
    else if (execContext instanceof QueryDataSpaceExecutionContext) {
        const protocol = new V1_QueryDataSpaceExecutionContext();
        protocol.dataSpacePath = execContext.dataSpacePath;
        protocol.executionKey = execContext.executionKey;
        return protocol;
    }
    else if (execContext instanceof QueryDataProductExecutionContext) {
        const protocol = new V1_QueryDataProductExecutionContext();
        protocol.dataProductPath = execContext.dataProductPath;
        protocol.executionKey = execContext.executionKey;
        return protocol;
    }
    throw new UnsupportedOperationError('Unsupported query execution context');
};
export const V1_transformQuery = (metamodel) => {
    const protocol = new V1_Query();
    if (metamodel.name) {
        protocol.name = metamodel.name;
    }
    if (metamodel.id) {
        protocol.id = metamodel.id;
    }
    if (metamodel.description) {
        protocol.description = metamodel.description;
    }
    if (metamodel.versionId) {
        protocol.versionId = metamodel.versionId;
    }
    if (metamodel.groupId) {
        protocol.groupId = metamodel.groupId;
    }
    if (metamodel.artifactId) {
        protocol.artifactId = metamodel.artifactId;
    }
    protocol.originalVersionId = metamodel.originalVersionId;
    if (metamodel.executionContext) {
        protocol.executionContext = V1_transformQueryExecutionContext(metamodel.executionContext);
    }
    if (metamodel.content) {
        protocol.content = metamodel.content;
    }
    protocol.owner = metamodel.owner;
    protocol.taggedValues = metamodel.taggedValues?.map((_taggedValue) => {
        const taggedValue = new V1_TaggedValue();
        taggedValue.tag = new V1_TagPtr();
        taggedValue.tag.profile = _taggedValue.profile;
        taggedValue.tag.value = _taggedValue.tag;
        taggedValue.value = _taggedValue.value;
        return taggedValue;
    });
    protocol.defaultParameterValues = metamodel.defaultParameterValues?.map((_defaultParams) => {
        const vDefault = new V1_QueryParameterValue();
        vDefault.name = _defaultParams.name;
        vDefault.content = _defaultParams.content;
        return vDefault;
    });
    protocol.stereotypes = metamodel.stereotypes?.map((_stereotype) => {
        const stereotype = new V1_StereotypePtr();
        stereotype.profile = _stereotype.profile;
        stereotype.value = _stereotype.stereotype;
        return stereotype;
    });
    if (metamodel.gridConfig) {
        protocol.gridConfig = metamodel.gridConfig;
    }
    return protocol;
};
export const V1_transformQuerySearchSpecification = (metamodel) => {
    const protocol = new V1_QuerySearchSpecification();
    if (metamodel.searchTermSpecification) {
        const termSpec = new V1_QuerySearchTermSpecification();
        termSpec.exactMatchName = metamodel.searchTermSpecification.exactMatchName;
        termSpec.includeOwner = metamodel.searchTermSpecification.includeOwner;
        termSpec.searchTerm = metamodel.searchTermSpecification.searchTerm;
        protocol.searchTermSpecification = termSpec;
    }
    protocol.limit = metamodel.limit;
    protocol.showCurrentUserQueriesOnly = metamodel.showCurrentUserQueriesOnly;
    protocol.projectCoordinates = metamodel.projectCoordinates?.map((_projectCoordinate) => {
        const projectCoordinate = new V1_QueryProjectCoordinates();
        projectCoordinate.groupId = _projectCoordinate.groupId;
        projectCoordinate.artifactId = _projectCoordinate.artifactId;
        return projectCoordinate;
    });
    protocol.taggedValues = metamodel.taggedValues?.map((_taggedValue) => {
        const taggedValue = new V1_TaggedValue();
        taggedValue.tag = new V1_TagPtr();
        taggedValue.tag.profile = _taggedValue.profile;
        taggedValue.tag.value = _taggedValue.tag;
        taggedValue.value = _taggedValue.value;
        return taggedValue;
    });
    protocol.stereotypes = metamodel.stereotypes?.map((_stereotype) => {
        const stereotype = new V1_StereotypePtr();
        stereotype.profile = _stereotype.profile;
        stereotype.value = _stereotype.stereotype;
        return stereotype;
    });
    protocol.combineTaggedValuesCondition =
        metamodel.combineTaggedValuesCondition;
    if (metamodel.sortByOption) {
        protocol.sortByOption = metamodel.sortByOption;
    }
    return protocol;
};
export const V1_buildLegacyServiceTestResult = (protocol) => {
    const metamodel = new DEPRECATED__ServiceTestResult();
    metamodel.name = guaranteeNonNullable(protocol.name, `Service test result 'name' field is missing`);
    metamodel.result = guaranteeNonNullable(protocol.result, `Service test result 'result' field is missing`);
    return metamodel;
};
export const V1_buildServiceRegistrationSuccess = (service, protocol) => {
    guaranteeNonNullable(protocol.serverURL, `Service registration result 'serverUrl' field is missing`);
    guaranteeNonNullable(protocol.pattern, `Service registration result 'pattern' field is missing`);
    guaranteeNonNullable(protocol.serviceInstanceId, `Service registration 'serviceInstanceId' field is missing`);
    return new ServiceRegistrationSuccess(service, protocol.serverURL, protocol.pattern, protocol.serviceInstanceId);
};
export const V1_buildGenerationProperty = (protocol) => {
    const metamodel = new GenerationProperty();
    metamodel.name = guaranteeNonNullable(protocol.name, `Generation property 'name' field is missing`);
    metamodel.description = guaranteeNonNullable(protocol.description, `Generation property 'description' field is missing`);
    metamodel.type = getGenerationPropertyItemType(guaranteeNonNullable(protocol.type, `Generation property 'type' field is missing`));
    if (protocol.items) {
        const generationPropertyItem = new GenerationPropertyItem();
        generationPropertyItem.types = protocol.items.types.map(getGenerationPropertyItemType);
        generationPropertyItem.enums = protocol.items.enums;
        metamodel.items = generationPropertyItem;
    }
    metamodel.defaultValue = protocol.defaultValue;
    metamodel.required = protocol.required;
    return metamodel;
};
export const V1_buildExternalFormatDescription = (protocol) => {
    assertNonEmptyString(protocol.name, `External configuration description 'name' field is missing`);
    const metamodel = new ExternalFormatDescription(protocol.name);
    metamodel.contentTypes = protocol.contentTypes;
    // model generation
    metamodel.supportsModelGeneration = protocol.supportsModelGeneration;
    metamodel.modelGenerationProperties = protocol.modelGenerationProperties.map(V1_buildGenerationProperty);
    // schema generation
    metamodel.supportsSchemaGeneration = protocol.supportsSchemaGeneration;
    metamodel.schemaGenerationProperties =
        protocol.schemaGenerationProperties.map(V1_buildGenerationProperty);
    return metamodel;
};
export const V1_buildGenerationOutput = (protocol) => {
    const metamodel = new GenerationOutput();
    metamodel.content = guaranteeNonNullable(protocol.content, `Generation output 'content' field is missing`);
    metamodel.fileName = guaranteeNonNullable(protocol.fileName, `Generation output 'fileName' field is missing`);
    metamodel.format = protocol.format;
    return metamodel;
};
export const V1_buildGenerationConfigurationDescription = (protocol) => {
    const metamodel = new GenerationConfigurationDescription();
    metamodel.key = guaranteeNonNullable(protocol.key, `Generation configuration description 'key' field is missing`);
    metamodel.label = guaranteeNonNullable(protocol.label, `Generation configuration description 'label' field is missing`);
    metamodel.properties = protocol.properties.map(V1_buildGenerationProperty);
    metamodel.generationMode = guaranteeNonNullable(Object.values(GenerationMode).find((mode) => mode === protocol.generationMode), `Generation configuration description 'generationMode' field is missing or not supported`);
    return metamodel;
};
export const V1_buildSourceInformation = (sourceInformation) => new SourceInformation(guaranteeNonNullable(sourceInformation.sourceId, `Source information 'sourceId' field is missing`), guaranteeNonNullable(sourceInformation.startLine, `Source information 'startLine' field is missing`), guaranteeNonNullable(sourceInformation.startColumn, `Source information 'startColumn' field is missing`), guaranteeNonNullable(sourceInformation.endLine, `Source information 'endLine' field is missing`), guaranteeNonNullable(sourceInformation.endColumn, `Source information 'endColumn' field is missing`));
export const V1_buildCompilationError = (protocol) => {
    const metamodel = new CompilationError(protocol.message);
    metamodel.sourceInformation = protocol.sourceInformation
        ? V1_buildSourceInformation(protocol.sourceInformation)
        : undefined;
    metamodel.trace = protocol.trace;
    return metamodel;
};
export const V1_buildParserError = (protocol) => {
    const metamodel = new ParserError(protocol.message);
    metamodel.sourceInformation = protocol.sourceInformation
        ? V1_buildSourceInformation(protocol.sourceInformation)
        : undefined;
    metamodel.trace = protocol.trace;
    return metamodel;
};
export const V1_buildEngineError = (protocol) => {
    const metamodel = new EngineError(protocol.message);
    metamodel.sourceInformation = protocol.sourceInformation
        ? V1_buildSourceInformation(protocol.sourceInformation)
        : undefined;
    return metamodel;
};
export const V1_buildExecutionError = (protocol) => {
    const executionError = new ExecutionError(protocol.message);
    executionError.stack = protocol.trace;
    return executionError;
};
export const V1_buildFunctionInfoAnalysis = (functionProtocols, graph) => {
    const functionInfos = functionProtocols.map((func) => {
        const functionInfo = new FunctionAnalysisInfo();
        functionInfo.functionPath = func.path;
        functionInfo.name = func.name;
        functionInfo.functionName =
            func.name.split(V1_buildFunctionSignatureSuffix(func))[0] ?? func.name;
        functionInfo.functionPrettyName = V1_buildFunctionPrettyName(func, {
            fullPath: true,
        });
        functionInfo.packagePath = func.package;
        functionInfo.returnType = V1_getGenericTypeFullPath(func.returnGenericType);
        functionInfo.parameterInfoList = func.parameters.map((param) => {
            const paramInfo = new FunctionAnalysisParameterInfo();
            paramInfo.multiplicity = graph.getMultiplicity(param.multiplicity.lowerBound, param.multiplicity.upperBound);
            paramInfo.name = param.name;
            paramInfo.type = param.genericType.rawType.fullPath;
            return paramInfo;
        });
        return functionInfo;
    });
    return functionInfos;
};
//# sourceMappingURL=V1_EngineHelper.js.map