/**
 * 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 { serialize, deserialize } from 'serializr';
import { UnsupportedOperationError, assertErrorThrown, guaranteeIsString, isString, } from '@finos/legend-shared';
import { V1_flatDataModelSchema, V1_FLAT_DATA_ELEMENT_PROTOCOL_TYPE, } from './serializationHelpers/V1_StoreSerializationHelper.js';
import { V1_mappingModelSchema, V1_MAPPING_ELEMENT_PROTOCOL_TYPE, } from './serializationHelpers/V1_MappingSerializationHelper.js';
import { V1_serviceModelSchema, V1_SERVICE_ELEMENT_PROTOCOL_TYPE, } from './serializationHelpers/V1_ServiceSerializationHelper.js';
import { V1_PACKAGEABLE_RUNTIME_ELEMENT_PROTOCOL_TYPE, V1_packageableRuntimeModelSchema, } from './serializationHelpers/V1_RuntimeSerializationHelper.js';
import { V1_PACKAGEABLE_CONNECTION_ELEMENT_PROTOCOL_TYPE, V1_packageableConnectionModelSchema, } from './serializationHelpers/V1_ConnectionSerializationHelper.js';
import { V1_FILE_GENERATION_ELEMENT_PROTOCOL_TYPE, V1_fileGenerationModelSchema, } from './serializationHelpers/V1_FileGenerationSerializationHelper.js';
import { V1_GENERATION_SPECIFICATION_ELEMENT_PROTOCOL_TYPE, V1_generationSpecificationsModelSchema, } from './serializationHelpers/V1_GenerationSpecificationSerializationHelper.js';
import { V1_SECTION_INDEX_ELEMENT_PROTOCOL_TYPE, V1_sectionIndexModelSchema, } from './serializationHelpers/V1_SectionIndexSerializationHelper.js';
import { V1_databaseModelSchema, V1_DATABASE_ELEMENT_PROTOCOL_TYPE, } from './serializationHelpers/V1_DatabaseSerializationHelper.js';
import { V1_associationModelSchema, V1_ASSOCIATION_ELEMENT_PROTOCOL_TYPE, V1_classModelSchema, V1_CLASS_ELEMENT_PROTOCOL_TYPE, V1_enumerationModelSchema, V1_ENUMERATION_ELEMENT_PROTOCOL_TYPE, V1_functionModelSchema, V1_FUNCTION_ELEMENT_PROTOCOL_TYPE, V1_measureModelSchema, V1_MEASURE_ELEMENT_PROTOCOL_TYPE, V1_profileModelSchema, V1_PROFILE_ELEMENT_PROTOCOL_TYPE, V1_INTERNAL__UnknownFunctionActivatorModelSchema, V1_snowflakeAppModelSchema, V1_snowflakeM2MUdfModelSchema, V1_SNOWFLAKE_APP_TYPE, V1_SNOWFLAKE_M2M_UDF_TYPE, V1_HostedServiceModelSchema, V1_HOSTED_SERVICE_TYPE, V1_MEM_SQL_TYPE, V1_MemSQLModelSchema, } from './serializationHelpers/V1_DomainSerializationHelper.js';
import { createPath } from '../../../../../../graph/MetaModelUtils.js';
import { V1_dataElementModelSchema, V1_DATA_ELEMENT_PROTOCOL_TYPE, } from './serializationHelpers/V1_DataElementSerializationHelper.js';
import { V1_executionEnvModelSchema, V1_EXECUTION_ENVIRONMENT_ELEMENT_PROTOCOL_TYPE, } from './serializationHelpers/V1_ExecutionEnvironmentSerializationHelper.js';
import { V1_INTERNAL__UnknownPackageableElement } from '../../model/packageableElements/V1_INTERNAL__UnknownPackageableElement.js';
import { V1_INTERNAL__UnknownStore } from '../../model/packageableElements/store/V1_INTERNAL__UnknownStore.js';
import { V1_INTERNAL__UnknownElement } from '../../model/packageableElements/V1_INTERNAL__UnknownElement.js';
import { V1_DATA_PRODUCT_ELEMENT_PROTOCOL_TYPE, } from '../../model/packageableElements/dataProduct/V1_DataProduct.js';
import { V1_dataProductModelSchema } from './serializationHelpers/V1_DataProductSerializationHelper.js';
import { V1_INGEST_DEFINITION_TYPE } from '../../model/packageableElements/ingest/V1_IngestDefinition.js';
import { V1_createIngestDef } from './serializationHelpers/V1_IngestSerializationHelper.js';
class V1_PackageableElementSerializer {
    extraElementProtocolSerializers = [];
    plugins;
    constructor(plugins) {
        this.extraElementProtocolSerializers = plugins.flatMap((plugin) => plugin.V1_getExtraElementProtocolSerializers?.() ?? []);
        this.plugins = plugins;
    }
    visit_PackageableElement(elementProtocol) {
        for (const serializer of this.extraElementProtocolSerializers) {
            const elementProtocolJson = serializer(elementProtocol, this.plugins);
            if (elementProtocolJson) {
                return elementProtocolJson;
            }
        }
        throw new UnsupportedOperationError(`Can't serialize protocol for element '${elementProtocol.path}': no compatible serializer available from plugins`);
    }
    visit_INTERNAL__UnknownElement(element) {
        return element.content;
    }
    visit_INTERNAL__UnknownPackageableElement(element) {
        return element.content;
    }
    visit_IngestDefinition(element) {
        return this.visit_INTERNAL__UnknownPackageableElement(element);
    }
    visit_INTERNAL__UnknownFunctionActivator(element) {
        return element.content;
    }
    visit_SnowflakeApp(element) {
        return serialize(V1_snowflakeAppModelSchema(this.plugins), element);
    }
    visit_SnowflakeM2MUdf(element) {
        return serialize(V1_snowflakeM2MUdfModelSchema(this.plugins), element);
    }
    visit_HostedService(element) {
        return serialize(V1_HostedServiceModelSchema(this.plugins), element);
    }
    visit_MemSQLFunction(element) {
        return serialize(V1_MemSQLModelSchema(this.plugins), element);
    }
    visit_INTERNAL__UnknownStore(element) {
        return element.content;
    }
    visit_Profile(element) {
        return serialize(V1_profileModelSchema, element);
    }
    visit_Enumeration(element) {
        return serialize(V1_enumerationModelSchema, element);
    }
    visit_Measure(element) {
        return serialize(V1_measureModelSchema, element);
    }
    visit_Class(element) {
        return serialize(V1_classModelSchema, element);
    }
    visit_Association(element) {
        return serialize(V1_associationModelSchema, element);
    }
    visit_ConcreteFunctionDefinition(element) {
        return serialize(V1_functionModelSchema(this.plugins), element);
    }
    visit_FlatData(element) {
        return serialize(V1_flatDataModelSchema, element);
    }
    visit_Database(element) {
        return serialize(V1_databaseModelSchema, element);
    }
    visit_DataProduct(element) {
        return serialize(V1_dataProductModelSchema(this.plugins), element);
    }
    visit_Mapping(element) {
        return serialize(V1_mappingModelSchema(this.plugins), element);
    }
    visit_Service(element) {
        return serialize(V1_serviceModelSchema(this.plugins), element);
    }
    visit_ExecutionEnvironmentInstance(element) {
        return serialize(V1_executionEnvModelSchema, element);
    }
    visit_PackageableRuntime(element) {
        return serialize(V1_packageableRuntimeModelSchema, element);
    }
    visit_PackageableConnection(element) {
        return serialize(V1_packageableConnectionModelSchema(this.plugins), element);
    }
    visit_FileGeneration(element) {
        return serialize(V1_fileGenerationModelSchema, element);
    }
    visit_GenerationSpecification(element) {
        return serialize(V1_generationSpecificationsModelSchema, element);
    }
    visit_SectionIndex(element) {
        return serialize(V1_sectionIndexModelSchema, element);
    }
    visit_DataElement(element) {
        return serialize(V1_dataElementModelSchema(this.plugins), element);
    }
}
export const V1_serializePackageableElement = (element, plugins) => {
    try {
        return element.accept_PackageableElementVisitor(new V1_PackageableElementSerializer(plugins));
    }
    catch (error) {
        assertErrorThrown(error);
        error.message = `Can't serialize element '${element.path}': ${error.message}`;
        throw error;
    }
};
export const V1_deserializePackageableElement = (json, plugins, subtypeInfo, classifierPathMappingMap, classifierPath) => {
    const packagePath = guaranteeIsString(json.package, `Can't deserialize element: element package is not a string`);
    const name = guaranteeIsString(json.name, `Can't deserialize element: element name is not a string`);
    const elementPath = createPath(packagePath, name);
    try {
        const extraElementProtocolDeserializers = plugins.flatMap((plugin) => plugin.V1_getExtraElementProtocolDeserializers?.() ?? []);
        switch (json._type) {
            case V1_PROFILE_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_profileModelSchema, json);
            case V1_ENUMERATION_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_enumerationModelSchema, json);
            case V1_MEASURE_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_measureModelSchema, json);
            case V1_CLASS_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_classModelSchema, json);
            case V1_ASSOCIATION_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_associationModelSchema, json);
            case V1_FUNCTION_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_functionModelSchema(plugins), json);
            case V1_FLAT_DATA_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_flatDataModelSchema, json);
            case V1_DATABASE_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_databaseModelSchema, json);
            case V1_MAPPING_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_mappingModelSchema(plugins), json);
            case V1_SERVICE_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_serviceModelSchema(plugins), json);
            case V1_EXECUTION_ENVIRONMENT_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_executionEnvModelSchema, json);
            case V1_PACKAGEABLE_CONNECTION_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_packageableConnectionModelSchema(plugins), json);
            case V1_PACKAGEABLE_RUNTIME_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_packageableRuntimeModelSchema, json);
            case V1_FILE_GENERATION_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_fileGenerationModelSchema, json);
            case V1_GENERATION_SPECIFICATION_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_generationSpecificationsModelSchema, json);
            case V1_SECTION_INDEX_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_sectionIndexModelSchema, json);
            case V1_DATA_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_dataElementModelSchema(plugins), json);
            case V1_SNOWFLAKE_APP_TYPE:
                return deserialize(V1_snowflakeAppModelSchema(plugins), json);
            case V1_SNOWFLAKE_M2M_UDF_TYPE:
                return deserialize(V1_snowflakeM2MUdfModelSchema(plugins), json);
            case V1_HOSTED_SERVICE_TYPE:
                return deserialize(V1_HostedServiceModelSchema(plugins), json);
            case V1_MEM_SQL_TYPE:
                return deserialize(V1_MemSQLModelSchema(plugins), json);
            case V1_DATA_PRODUCT_ELEMENT_PROTOCOL_TYPE:
                return deserialize(V1_dataProductModelSchema(plugins), json);
            case V1_INGEST_DEFINITION_TYPE:
                return V1_createIngestDef(name, packagePath, json);
            default: {
                for (const deserializer of extraElementProtocolDeserializers) {
                    const protocol = deserializer(json, plugins);
                    if (protocol) {
                        return protocol;
                    }
                }
                if (subtypeInfo && isString(json._type)) {
                    if (subtypeInfo.functionActivatorSubtypes.includes(json._type)) {
                        const protocol = deserialize(V1_INTERNAL__UnknownFunctionActivatorModelSchema, json);
                        protocol.content = json;
                        return protocol;
                    }
                    if (subtypeInfo.storeSubtypes.includes(json._type)) {
                        const protocol = new V1_INTERNAL__UnknownStore();
                        protocol.name = name;
                        protocol.package = packagePath;
                        protocol.content = json;
                        return protocol;
                    }
                }
                if (classifierPathMappingMap && isString(json._type)) {
                    if (classifierPathMappingMap.has(json._type)) {
                        // Fall back to create unknown stub if supported in engine but not studio
                        const protocol = new V1_INTERNAL__UnknownPackageableElement();
                        protocol.name = name;
                        protocol.package = packagePath;
                        protocol.content = json;
                        return protocol;
                    }
                }
                // Fall back to create unknown stub if not supported in engine
                const protocol = new V1_INTERNAL__UnknownElement();
                protocol.name = name;
                protocol.package = packagePath;
                protocol.content = json;
                protocol.classifierPath = classifierPath ?? '';
                return protocol;
            }
        }
    }
    catch (error) {
        assertErrorThrown(error);
        error.message = `Can't deserialize element '${elementPath}': ${error.message}`;
        throw error;
    }
};
//# sourceMappingURL=V1_PackageableElementSerialization.js.map