/**
 * 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 { createModelSchema, primitive, serialize, SKIP, list, custom, deserialize, optional, } from 'serializr';
import { usingConstantValueSchema, UnsupportedOperationError, usingModelSchema, guaranteeIsString, isString, isPlainObject, optionalCustom, } from '@finos/legend-shared';
import { V1_Variable } from '../../../model/valueSpecification/V1_Variable.js';
import { V1_RootGraphFetchTree } from '../../../model/valueSpecification/raw/classInstance/graph/V1_RootGraphFetchTree.js';
import { V1_Lambda } from '../../../model/valueSpecification/raw/V1_Lambda.js';
import { V1_EnumValue } from '../../../model/valueSpecification/raw/V1_EnumValue.js';
import { V1_Path } from '../../../model/valueSpecification/raw/classInstance/path/V1_Path.js';
import { V1_AppliedFunction } from '../../../model/valueSpecification/application/V1_AppliedFunction.js';
import { V1_Collection } from '../../../model/valueSpecification/raw/V1_Collection.js';
import { V1_CDecimal } from '../../../model/valueSpecification/raw/V1_CDecimal.js';
import { V1_CInteger } from '../../../model/valueSpecification/raw/V1_CInteger.js';
import { V1_CString } from '../../../model/valueSpecification/raw/V1_CString.js';
import { V1_CFloat } from '../../../model/valueSpecification/raw/V1_CFloat.js';
import { V1_CDateTime } from '../../../model/valueSpecification/raw/V1_CDateTime.js';
import { V1_CStrictDate } from '../../../model/valueSpecification/raw/V1_CStrictDate.js';
import { V1_CStrictTime } from '../../../model/valueSpecification/raw/V1_CStrictTime.js';
import { V1_CLatestDate } from '../../../model/valueSpecification/raw/V1_CLatestDate.js';
import { V1_CBoolean } from '../../../model/valueSpecification/raw/V1_CBoolean.js';
import { V1_AggregateValue } from '../../../model/valueSpecification/raw/classInstance/V1_AggregateValue.js';
import { V1_Pair } from '../../../model/valueSpecification/raw/classInstance/V1_Pair.js';
import { V1_RuntimeInstance } from '../../../model/valueSpecification/raw/classInstance/V1_RuntimeInstance.js';
import { V1_ExecutionContextInstance } from '../../../model/valueSpecification/raw/classInstance/V1_ExecutionContextInstance.js';
import { V1_PropertyGraphFetchTree } from '../../../model/valueSpecification/raw/classInstance/graph/V1_PropertyGraphFetchTree.js';
import { V1_SubTypeGraphFetchTree } from '../../../model/valueSpecification/raw/classInstance/graph/V1_SubTypeGraphFetchTree.js';
import { V1_SerializationConfig } from '../../../model/valueSpecification/raw/classInstance/V1_SerializationConfig.js';
import { V1_KeyExpression } from '../../../model/valueSpecification/raw/V1_KeyExpression.js';
import { V1_PureList } from '../../../model/valueSpecification/raw/classInstance/V1_PureList.js';
import { V1_TDSAggregateValue } from '../../../model/valueSpecification/raw/classInstance/V1_TDSAggregateValue.js';
import { V1_TDSColumnInformation } from '../../../model/valueSpecification/raw/classInstance/V1_TDSColumnInformation.js';
import { V1_TDSSortInformation } from '../../../model/valueSpecification/raw/classInstance/V1_TDSSortInformation.js';
import { V1_TDSOlapRank } from '../../../model/valueSpecification/raw/classInstance/V1_TDSOlapRank.js';
import { V1_TDSOlapAggregation } from '../../../model/valueSpecification/raw/classInstance/V1_TDSOlapAggregation.js';
import { V1_ColSpecArray } from '../../../model/valueSpecification/raw/classInstance/relation/V1_ColSpecArray.js';
import { V1_ColSpec } from '../../../model/valueSpecification/raw/classInstance/relation/V1_ColSpec.js';
import { V1_DataProductAccessor, V1_RelationStoreAccessor, V1_SQLAccessor, } from '../../../model/valueSpecification/raw/classInstance/relation/V1_RelationStoreAccessor.js';
import { V1_multiplicityModelSchema } from './V1_CoreSerializationHelper.js';
import { V1_PropertyPathElement } from '../../../model/valueSpecification/raw/classInstance/path/V1_PropertyPathElement.js';
import { V1_AppliedProperty } from '../../../model/valueSpecification/application/V1_AppliedProperty.js';
import { V1_serializeRuntime } from './V1_RuntimeSerializationHelper.js';
import { V1_AnalyticsExecutionContext } from '../../../model/valueSpecification/raw/executionContext/V1_AnalyticsExecutionContext.js';
import { V1_BaseExecutionContext } from '../../../model/valueSpecification/raw/executionContext/V1_BaseExecutionContext.js';
import { V1_PackageableElementPtr } from '../../../model/valueSpecification/raw/V1_PackageableElementPtr.js';
import { V1_EngineRuntime } from '../../../model/packageableElements/runtime/V1_Runtime.js';
import { V1_GenericTypeInstance } from '../../../model/valueSpecification/raw/V1_GenericTypeInstance.js';
import { V1_Multiplicity } from '../../../model/packageableElements/domain/V1_Multiplicity.js';
import { V1_ClassInstance } from '../../../model/valueSpecification/raw/V1_ClassInstance.js';
import { V1_CByteArray } from '../../../model/valueSpecification/raw/V1_CByteArray.js';
import { V1_deserializeGenericType, V1_genericTypeModelSchema, } from './V1_TypeSerializationHelper.js';
import { V1_createGenericTypeWithElementPath } from '../../../helpers/V1_DomainHelper.js';
var V1_ExecutionContextType;
(function (V1_ExecutionContextType) {
    V1_ExecutionContextType["BASE_EXECUTION_CONTEXT"] = "BaseExecutionContext";
    V1_ExecutionContextType["ANALYTICS_EXECUTION_CONTEXT"] = "AnalyticsExecutionContext";
})(V1_ExecutionContextType || (V1_ExecutionContextType = {}));
var V1_PathElementType;
(function (V1_PathElementType) {
    V1_PathElementType["PROPERTY_PATH_ELEMENT"] = "propertyPath";
})(V1_PathElementType || (V1_PathElementType = {}));
export var V1_GraphFetchTreeType;
(function (V1_GraphFetchTreeType) {
    V1_GraphFetchTreeType["PROPERTY_GRAPH_FETCH_TREE"] = "propertyGraphFetchTree";
})(V1_GraphFetchTreeType || (V1_GraphFetchTreeType = {}));
export var V1_ClassInstanceType;
(function (V1_ClassInstanceType) {
    V1_ClassInstanceType["ROOT_GRAPH_FETCH_TREE"] = "rootGraphFetchTree";
    V1_ClassInstanceType["SUBTYPE_GRAPH_FETCH_TREE"] = "subTypeGraphFetchTree";
    V1_ClassInstanceType["PATH"] = "path";
    V1_ClassInstanceType["AGGREGATE_VALUE"] = "aggregateValue";
    V1_ClassInstanceType["EXECUTION_CONTEXT_INSTANCE"] = "executionContextInstance";
    V1_ClassInstanceType["PAIR"] = "pair";
    V1_ClassInstanceType["PURE_LIST"] = "listInstance";
    V1_ClassInstanceType["RUNTIME_INSTANCE"] = "runtimeInstance";
    V1_ClassInstanceType["SERIALIZATION_CONFIG"] = "alloySerializationConfig";
    V1_ClassInstanceType["COL_SPEC"] = "colSpec";
    V1_ClassInstanceType["COL_SPEC_ARRAY"] = "colSpecArray";
    V1_ClassInstanceType["RELATION_STORE_ACCESSOR"] = ">";
    V1_ClassInstanceType["INGEST_ACCESSOR"] = "I";
    V1_ClassInstanceType["DATA_PRODUCT_ACCESSOR"] = "P";
    V1_ClassInstanceType["SQL_ACCESSOR"] = "SQL";
    V1_ClassInstanceType["TDS_AGGREGATE_VALUE"] = "tdsAggregateValue";
    V1_ClassInstanceType["TDS_COLUMN_INFORMATION"] = "tdsColumnInformation";
    V1_ClassInstanceType["TDS_SORT_INFORMATION"] = "tdsSortInformation";
    V1_ClassInstanceType["TDS_OLAP_RANK"] = "tdsOlapRank";
    V1_ClassInstanceType["TDS_OLAP_AGGREGATION"] = "tdsOlapAggregation";
})(V1_ClassInstanceType || (V1_ClassInstanceType = {}));
var V1_ValueSpecificationType;
(function (V1_ValueSpecificationType) {
    V1_ValueSpecificationType["VARIABLE"] = "var";
    V1_ValueSpecificationType["LAMBDA"] = "lambda";
    V1_ValueSpecificationType["KEY_EXPRESSION"] = "keyExpression";
    V1_ValueSpecificationType["APPLIED_FUNCTION"] = "func";
    V1_ValueSpecificationType["APPLIED_PROPERTY"] = "property";
    V1_ValueSpecificationType["PACKAGEABLE_ELEMENT_PTR"] = "packageableElementPtr";
    V1_ValueSpecificationType["GENERIC_TYPE_INSTANCE"] = "genericTypeInstance";
    V1_ValueSpecificationType["ENUM_VALUE"] = "enumValue";
    V1_ValueSpecificationType["COLLECTION"] = "collection";
    V1_ValueSpecificationType["CINTEGER"] = "integer";
    V1_ValueSpecificationType["CDECIMAL"] = "decimal";
    V1_ValueSpecificationType["CSTRING"] = "string";
    V1_ValueSpecificationType["CBOOLEAN"] = "boolean";
    V1_ValueSpecificationType["CBYTEARRAY"] = "byteArray";
    V1_ValueSpecificationType["CFLOAT"] = "float";
    V1_ValueSpecificationType["CDATETIME"] = "dateTime";
    V1_ValueSpecificationType["CSTRICTDATE"] = "strictDate";
    V1_ValueSpecificationType["CSTRICTTIME"] = "strictTime";
    V1_ValueSpecificationType["CLATESTDATE"] = "latestDate";
    V1_ValueSpecificationType["CLASS_INSTANCE"] = "classInstance";
    // ------------------------------ DEPRECATED ----------------------------------
    V1_ValueSpecificationType["HACKED_CLASS"] = "hackedClass";
    V1_ValueSpecificationType["HACKED_UNIT"] = "hackedUnit";
    V1_ValueSpecificationType["UNIT_TYPE"] = "unitType";
    V1_ValueSpecificationType["PRIMITIVE_TYPE"] = "primitiveType";
    V1_ValueSpecificationType["CLASS"] = "class";
    V1_ValueSpecificationType["ENUM"] = "enum";
    V1_ValueSpecificationType["MAPPING_INSTANCE"] = "mappingInstance";
})(V1_ValueSpecificationType || (V1_ValueSpecificationType = {}));
// ---------------------------------------- Value Specification --------------------------------------
export const V1_variableModelSchema = createModelSchema(V1_Variable, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.VARIABLE),
    genericType: optionalCustom((val) => serialize(V1_genericTypeModelSchema, val), (val) => V1_deserializeGenericType(val), {
        beforeDeserialize: function (callback, jsonValue, jsonParentValue) {
            /** @backwardCompatibility */
            if (jsonParentValue.class !== undefined &&
                jsonParentValue.genericType === undefined) {
                callback(null, jsonParentValue.class);
            }
            else {
                callback(null, jsonParentValue.genericType);
            }
        },
    }),
    multiplicity: usingModelSchema(V1_multiplicityModelSchema),
    name: primitive(),
});
export const V1_lambdaModelSchema = (plugins) => createModelSchema(V1_Lambda, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.LAMBDA),
    body: list(custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins))),
    parameters: list(usingModelSchema(V1_variableModelSchema)),
});
const keyExpressionModelSchema = (plugins) => createModelSchema(V1_KeyExpression, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.KEY_EXPRESSION),
    add: optional(primitive()),
    expression: custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins)),
    key: custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins)),
});
const appliedFunctionModelSchema = (plugins) => createModelSchema(V1_AppliedFunction, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.APPLIED_FUNCTION),
    function: primitive(),
    parameters: list(custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins))),
});
const appliedPropertyModelSchema = (plugins) => createModelSchema(V1_AppliedProperty, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.APPLIED_PROPERTY),
    class: optional(primitive()),
    parameters: list(custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins))),
    property: primitive(),
});
export const V1_packageableElementPtrSchema = (isType) => createModelSchema(V1_PackageableElementPtr, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.PACKAGEABLE_ELEMENT_PTR),
    fullPath: primitive(),
});
const genericTypeInstanceSchema = (plugins) => createModelSchema(V1_GenericTypeInstance, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.GENERIC_TYPE_INSTANCE),
    genericType: custom((val) => serialize(V1_genericTypeModelSchema, val), (val) => V1_deserializeGenericType(val), {
        beforeDeserialize: function (callback, jsonValue, jsonParentValue) {
            /** @backwardCompatibility */
            if (jsonParentValue.fullPath !== undefined &&
                jsonParentValue.genericType === undefined) {
                callback(null, jsonParentValue.fullPath);
            }
            else {
                callback(null, jsonParentValue.genericType);
            }
        },
    }),
});
/** @backwardCompatibility */
const deserializeHackedUnit = (json) => {
    const protocol = new V1_GenericTypeInstance();
    if (isString(json.unitType)) {
        protocol.genericType = V1_createGenericTypeWithElementPath(json.unitType);
    }
    else {
        protocol.genericType = V1_createGenericTypeWithElementPath(guaranteeIsString(json.fullPath, `Can't deserialize hacked unit: either field 'fullPath' or 'unitType' must be a non-empty string`));
    }
    return protocol;
};
/** @backwardCompatibility */
const deserializeHackedClass = (json) => {
    const protocol = new V1_GenericTypeInstance();
    protocol.genericType = V1_createGenericTypeWithElementPath(guaranteeIsString(json.fullPath, `Can't deserialize hacked class: field 'fullPath' must be a non-empty string`));
    return protocol;
};
const collectionModelSchema = (plugins) => createModelSchema(V1_Collection, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.COLLECTION),
    multiplicity: usingModelSchema(V1_multiplicityModelSchema),
    values: list(custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins))),
});
const enumValueModelSchema = createModelSchema(V1_EnumValue, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.ENUM_VALUE),
    fullPath: primitive(),
    value: primitive(),
});
const CDecimalModelSchema = createModelSchema(V1_CDecimal, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CDECIMAL),
    value: primitive(),
});
const CIntegerModelSchema = createModelSchema(V1_CInteger, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CINTEGER),
    value: primitive(),
});
const CStringModelSchema = createModelSchema(V1_CString, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CSTRING),
    value: primitive(),
});
const CFloatModelSchema = createModelSchema(V1_CFloat, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CFLOAT),
    value: primitive(),
});
const CDateTimeModelSchema = createModelSchema(V1_CDateTime, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CDATETIME),
    value: primitive(),
});
const CStrictTimeModelSchema = createModelSchema(V1_CStrictTime, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CSTRICTTIME),
    value: primitive(),
});
const CStrictDateModelSchema = createModelSchema(V1_CStrictDate, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CSTRICTDATE),
    value: primitive(),
});
const CLatestDateModelSchema = createModelSchema(V1_CLatestDate, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CLATESTDATE),
});
const CBooleanModelSchema = createModelSchema(V1_CBoolean, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CBOOLEAN),
    value: primitive(),
});
const CByteArrayModelSchema = createModelSchema(V1_CByteArray, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CBYTEARRAY),
    value: primitive(),
});
/** @backwardCompatibility */
const deserializePrimitiveValueSpecification = (json, plugins, deserializer) => {
    if (Array.isArray(json.values)) {
        if (json.values.length === 0) {
            const collection = new V1_Collection();
            collection.multiplicity = V1_Multiplicity.ZERO;
            return collection;
        }
        else if (json.values.length === 1) {
            return deserializer({
                ...json,
                value: json.values[0],
            });
        }
        else {
            return V1_deserializeValueSpecification({
                ...json,
                _type: V1_ValueSpecificationType.COLLECTION,
            }, plugins);
        }
    }
    return deserializer(json);
};
// ---------------------------------------- Class Instance --------------------------------------
const classInstanceModelSchema = (plugins) => createModelSchema(V1_ClassInstance, {
    _type: usingConstantValueSchema(V1_ValueSpecificationType.CLASS_INSTANCE),
    multiplicity: usingModelSchema(V1_multiplicityModelSchema),
    type: primitive(),
    value: custom((val) => V1_serializeClassInstanceValue(val, plugins), (val, context) => V1_deserializeClassInstanceValue(val, context.json.type, plugins)),
});
// path
const propertyPathElementModelSchema = (plugins) => createModelSchema(V1_PropertyPathElement, {
    _type: usingConstantValueSchema(V1_PathElementType.PROPERTY_PATH_ELEMENT),
    property: primitive(),
    parameters: list(custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins))),
});
function V1_serializePathElement(protocol, plugins) {
    if (protocol instanceof V1_PropertyPathElement) {
        return serialize(propertyPathElementModelSchema(plugins), protocol);
    }
    return SKIP;
}
function V1_deserializePathElement(json, plugins) {
    switch (json._type) {
        case V1_PathElementType.PROPERTY_PATH_ELEMENT:
            return deserialize(propertyPathElementModelSchema(plugins), json);
        default:
            return SKIP;
    }
}
const pathModelSchema = (plugins) => createModelSchema(V1_Path, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.PATH),
    name: primitive(),
    startType: primitive(),
    path: list(custom((val) => V1_serializePathElement(val, plugins), (val) => V1_deserializePathElement(val, plugins))),
});
// graph fetch tree
const rootGraphFetchTreeModelSchema = (plugins) => createModelSchema(V1_RootGraphFetchTree, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.ROOT_GRAPH_FETCH_TREE),
    class: primitive(),
    subTrees: list(custom((val) => V1_serializeGraphFetchTree(val, plugins), (val) => V1_deserializeGraphFetchTree(val, plugins))),
    subTypeTrees: list(custom((val) => V1_serializeGraphFetchTree(val, plugins), (val) => V1_deserializeGraphFetchTree(val, plugins))),
});
const propertyGraphFetchTreeModelSchema = (plugins) => createModelSchema(V1_PropertyGraphFetchTree, {
    _type: usingConstantValueSchema(V1_GraphFetchTreeType.PROPERTY_GRAPH_FETCH_TREE),
    alias: optional(primitive()),
    parameters: list(custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins))),
    property: primitive(),
    subTrees: list(custom((val) => V1_serializeGraphFetchTree(val, plugins), (val) => V1_deserializeGraphFetchTree(val, plugins))),
    subTypeTrees: list(custom((val) => V1_serializeGraphFetchTree(val, plugins), (val) => V1_deserializeGraphFetchTree(val, plugins))),
    subType: optional(primitive()),
});
const subTypeGraphFetchTreeModelSchema = (plugins) => createModelSchema(V1_SubTypeGraphFetchTree, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.SUBTYPE_GRAPH_FETCH_TREE),
    subTrees: list(custom((val) => V1_serializeGraphFetchTree(val, plugins), (val) => V1_deserializeGraphFetchTree(val, plugins))),
    subTypeClass: primitive(),
});
export function V1_serializeGraphFetchTree(protocol, plugins) {
    // we have further subtypes of Property and RootGraph Tree so we should look at the extensions first
    const serializers = plugins.flatMap((plugin) => plugin.V1_getExtraGraphFetchProtocolSerializers?.() ?? []);
    for (const serializer of serializers) {
        const json = serializer(protocol, plugins);
        if (json) {
            return json;
        }
    }
    if (protocol instanceof V1_PropertyGraphFetchTree) {
        return serialize(propertyGraphFetchTreeModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_RootGraphFetchTree) {
        return serialize(rootGraphFetchTreeModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_SubTypeGraphFetchTree) {
        return serialize(subTypeGraphFetchTreeModelSchema(plugins), protocol);
    }
    throw new UnsupportedOperationError(`Can't serialize graph fetch tree: no compatible serializer available from plugins`, protocol);
}
export function V1_deserializeGraphFetchTree(json, plugins) {
    switch (json._type) {
        case V1_GraphFetchTreeType.PROPERTY_GRAPH_FETCH_TREE:
            return deserialize(propertyGraphFetchTreeModelSchema(plugins), json);
        case V1_ClassInstanceType.ROOT_GRAPH_FETCH_TREE:
            return deserialize(rootGraphFetchTreeModelSchema(plugins), json);
        case V1_ClassInstanceType.SUBTYPE_GRAPH_FETCH_TREE:
            return deserialize(subTypeGraphFetchTreeModelSchema(plugins), json);
        default: {
            const deserializers = plugins.flatMap((plugin) => plugin.V1_getExtraGraphFetchProtocolDeserializers?.() ?? []);
            for (const deserializer of deserializers) {
                const protocol = deserializer(json, plugins);
                if (protocol) {
                    return protocol;
                }
            }
            throw new UnsupportedOperationError(`Can't deserialize graph fetch tree node of type '${json._type}': no compatible deserializer available from plugins`);
        }
    }
}
// execution context
const analyticsExecutionContextModelSchema = (plugins) => createModelSchema(V1_AnalyticsExecutionContext, {
    _type: usingConstantValueSchema(V1_ExecutionContextType.ANALYTICS_EXECUTION_CONTEXT),
    enableConstraints: optional(primitive()),
    queryTimeOutInSeconds: optional(primitive()),
    toFlowSetFunction: usingModelSchema(V1_lambdaModelSchema(plugins)),
    useAnalytics: primitive(),
});
const baseExecutionContextModelSchema = createModelSchema(V1_BaseExecutionContext, {
    _type: usingConstantValueSchema(V1_ExecutionContextType.BASE_EXECUTION_CONTEXT),
    enableConstraints: optional(primitive()),
    queryTimeOutInSeconds: optional(primitive()),
});
function V1_serializeExecutionContext(protocol, plugins) {
    if (protocol instanceof V1_AnalyticsExecutionContext) {
        return serialize(analyticsExecutionContextModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_BaseExecutionContext) {
        return serialize(baseExecutionContextModelSchema, protocol);
    }
    return SKIP;
}
function V1_deserializeExecutionContext(json, plugins) {
    switch (json._type) {
        case V1_ExecutionContextType.ANALYTICS_EXECUTION_CONTEXT:
            return deserialize(analyticsExecutionContextModelSchema(plugins), json);
        case V1_ExecutionContextType.BASE_EXECUTION_CONTEXT:
            return deserialize(baseExecutionContextModelSchema, json);
        default:
            return SKIP;
    }
}
const executionContextInstanceModelSchema = (plugins) => createModelSchema(V1_ExecutionContextInstance, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.EXECUTION_CONTEXT_INSTANCE),
    executionContext: custom((val) => V1_serializeExecutionContext(val, plugins), (val) => V1_deserializeExecutionContext(val, plugins)),
});
// others
const aggregationValueModelSchema = (plugins) => createModelSchema(V1_AggregateValue, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.AGGREGATE_VALUE),
    mapFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
    aggregateFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
});
const pairModelSchema = (plugins) => createModelSchema(V1_Pair, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.PAIR),
    first: custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins)),
    second: custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins)),
});
const runtimeInstanceModelSchema = createModelSchema(V1_RuntimeInstance, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.RUNTIME_INSTANCE),
    runtime: custom((val) => V1_serializeRuntime(val), (val) => deserialize(V1_EngineRuntime, val)),
});
const pureListModelSchema = (plugins) => createModelSchema(V1_PureList, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.PURE_LIST),
    values: list(custom((val) => V1_serializeValueSpecification(val, plugins), (val) => V1_deserializeValueSpecification(val, plugins))),
});
const serializationConfigModelSchema = createModelSchema(V1_SerializationConfig, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.SERIALIZATION_CONFIG),
    includeType: optional(primitive()),
    typeKeyName: primitive(),
    includeEnumTypee: optional(primitive()),
    removePropertiesWithNullValuese: optional(primitive()),
    removePropertiesWithEmptySetse: optional(primitive()),
    fullyQualifiedTypePathe: optional(primitive()),
    includeObjectReferencee: optional(primitive()),
});
// TDS
const tdsAggregrateValueModelSchema = (plugins) => createModelSchema(V1_TDSAggregateValue, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.TDS_AGGREGATE_VALUE),
    name: primitive(),
    pmapFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
    aggregateFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
});
const tdsColumnInformationModelSchema = (plugins) => createModelSchema(V1_TDSColumnInformation, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.TDS_COLUMN_INFORMATION),
    name: primitive(),
    columnFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
});
const tdsSortInformationModelSchema = createModelSchema(V1_TDSSortInformation, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.TDS_SORT_INFORMATION),
    column: primitive(),
    direction: primitive(),
});
const relationStoreAccessorModelSchema = createModelSchema(V1_RelationStoreAccessor, {
    path: list(primitive()),
    metadata: optional(primitive()),
});
const dataProductAccessorModelSchema = createModelSchema(V1_DataProductAccessor, {
    path: list(primitive()),
    parameters: list(primitive()),
});
const sqlAccessorModelSchema = createModelSchema(V1_SQLAccessor, {
    sql: primitive(),
});
const colSpecModelSchema = (plugins) => createModelSchema(V1_ColSpec, {
    function1: optional(usingModelSchema(V1_lambdaModelSchema(plugins))),
    function2: optional(usingModelSchema(V1_lambdaModelSchema(plugins))),
    name: primitive(),
    type: optional(primitive()),
});
const colSpecArrayModelSchema = (plugins) => createModelSchema(V1_ColSpecArray, {
    colSpecs: list(usingModelSchema(colSpecModelSchema(plugins))),
});
const tdsOlapRankModelSchema = (plugins) => createModelSchema(V1_TDSOlapRank, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.TDS_OLAP_RANK),
    function: usingModelSchema(V1_lambdaModelSchema(plugins)),
});
const tdsOlapAggregationModelSchema = (plugins) => createModelSchema(V1_TDSOlapAggregation, {
    _type: usingConstantValueSchema(V1_ClassInstanceType.TDS_OLAP_AGGREGATION),
    function: usingModelSchema(V1_lambdaModelSchema(plugins)),
    columnName: primitive(),
});
export function V1_deserializeClassInstanceValue(json, type, plugins) {
    switch (type) {
        case V1_ClassInstanceType.PATH:
            return deserialize(pathModelSchema(plugins), json);
        case V1_ClassInstanceType.ROOT_GRAPH_FETCH_TREE:
            return deserialize(rootGraphFetchTreeModelSchema(plugins), json);
        case V1_ClassInstanceType.AGGREGATE_VALUE:
            return deserialize(aggregationValueModelSchema(plugins), json);
        case V1_ClassInstanceType.EXECUTION_CONTEXT_INSTANCE:
            return deserialize(executionContextInstanceModelSchema(plugins), json);
        case V1_ClassInstanceType.PAIR:
            return deserialize(pairModelSchema(plugins), json);
        case V1_ClassInstanceType.PURE_LIST:
            return deserialize(pureListModelSchema(plugins), json);
        case V1_ClassInstanceType.RUNTIME_INSTANCE:
            return deserialize(runtimeInstanceModelSchema, json);
        case V1_ClassInstanceType.SERIALIZATION_CONFIG:
            return deserialize(serializationConfigModelSchema, json);
        case V1_ClassInstanceType.TDS_AGGREGATE_VALUE:
            return deserialize(tdsAggregrateValueModelSchema(plugins), json);
        case V1_ClassInstanceType.TDS_COLUMN_INFORMATION:
            return deserialize(tdsColumnInformationModelSchema(plugins), json);
        case V1_ClassInstanceType.TDS_OLAP_AGGREGATION:
            return deserialize(tdsOlapAggregationModelSchema(plugins), json);
        case V1_ClassInstanceType.TDS_OLAP_RANK:
            return deserialize(tdsOlapRankModelSchema(plugins), json);
        case V1_ClassInstanceType.TDS_SORT_INFORMATION:
            return deserialize(tdsSortInformationModelSchema, json);
        case V1_ClassInstanceType.COL_SPEC:
            return deserialize(colSpecModelSchema(plugins), json);
        case V1_ClassInstanceType.COL_SPEC_ARRAY:
            return deserialize(colSpecArrayModelSchema(plugins), json);
        case V1_ClassInstanceType.RELATION_STORE_ACCESSOR:
        case V1_ClassInstanceType.INGEST_ACCESSOR:
            return deserialize(relationStoreAccessorModelSchema, json);
        case V1_ClassInstanceType.DATA_PRODUCT_ACCESSOR:
            return deserialize(dataProductAccessorModelSchema, json);
        case V1_ClassInstanceType.SQL_ACCESSOR:
            return deserialize(sqlAccessorModelSchema, json);
        default: {
            const deserializers = plugins.flatMap((plugin) => plugin.V1_getExtraClassInstanceValueProtocolDeserializers?.() ?? []);
            for (const deserializer of deserializers) {
                const protocol = deserializer(json, type, plugins);
                if (protocol) {
                    return protocol;
                }
            }
            throw new UnsupportedOperationError(`Can't deserialize value specification of type '${json._type}': no compatible deserializer available from plugins`);
        }
    }
}
export function V1_serializeClassInstanceValue(protocol, plugins) {
    if (protocol instanceof V1_Path) {
        return serialize(pathModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_RootGraphFetchTree) {
        return serialize(rootGraphFetchTreeModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_ExecutionContextInstance) {
        return serialize(executionContextInstanceModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_AggregateValue) {
        return serialize(aggregationValueModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_Pair) {
        return serialize(pairModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_PureList) {
        return serialize(pureListModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_RuntimeInstance) {
        return serialize(runtimeInstanceModelSchema, protocol);
    }
    else if (protocol instanceof V1_SerializationConfig) {
        return serialize(serializationConfigModelSchema, protocol);
    }
    else if (protocol instanceof V1_TDSAggregateValue) {
        return serialize(tdsAggregrateValueModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_TDSColumnInformation) {
        return serialize(tdsColumnInformationModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_TDSOlapAggregation) {
        return serialize(tdsOlapAggregationModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_TDSOlapRank) {
        return serialize(tdsOlapRankModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_TDSSortInformation) {
        return serialize(tdsSortInformationModelSchema, protocol);
    }
    else if (protocol instanceof V1_ColSpec) {
        return serialize(colSpecModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_ColSpecArray) {
        return serialize(colSpecArrayModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_RelationStoreAccessor) {
        return serialize(relationStoreAccessorModelSchema, protocol);
    }
    else if (protocol instanceof V1_DataProductAccessor) {
        return serialize(dataProductAccessorModelSchema, protocol);
    }
    else if (protocol instanceof V1_SQLAccessor) {
        return serialize(sqlAccessorModelSchema, protocol);
    }
    const serializers = plugins.flatMap((plugin) => plugin.V1_getExtraClassInstanceValueProtocolSerializers?.() ?? []);
    for (const serializer of serializers) {
        const json = serializer(protocol, plugins);
        if (json) {
            return json;
        }
    }
    throw new UnsupportedOperationError(`Can't serialize class instance value: no compatible serializer available from plugins`, protocol);
}
// ---------------------------------------- Serialization Methods --------------------------------------
class V1_ValueSpecificationSerializer {
    plugins = [];
    constructor(plugins) {
        this.plugins = plugins;
    }
    visit_INTERNAL__UnknownValueSpecfication(valueSpecification) {
        return valueSpecification.content;
    }
    visit_Variable(valueSpecification) {
        return serialize(V1_variableModelSchema, valueSpecification);
    }
    visit_Lambda(valueSpecification) {
        return serialize(V1_lambdaModelSchema(this.plugins), valueSpecification);
    }
    visit_KeyExpression(valueSpecification) {
        return serialize(keyExpressionModelSchema(this.plugins), valueSpecification);
    }
    visit_PackageableElementPtr(valueSpecification) {
        return serialize(V1_packageableElementPtrSchema(), valueSpecification);
    }
    visit_GenericTypeInstance(valueSpecification) {
        return serialize(genericTypeInstanceSchema(this.plugins), valueSpecification);
    }
    visit_AppliedFunction(valueSpecification) {
        return serialize(appliedFunctionModelSchema(this.plugins), valueSpecification);
    }
    visit_AppliedProperty(valueSpecification) {
        return serialize(appliedPropertyModelSchema(this.plugins), valueSpecification);
    }
    visit_Collection(valueSpecification) {
        return serialize(collectionModelSchema(this.plugins), valueSpecification);
    }
    visit_EnumValue(valueSpecification) {
        return serialize(enumValueModelSchema, valueSpecification);
    }
    visit_CInteger(valueSpecification) {
        return serialize(CIntegerModelSchema, valueSpecification);
    }
    visit_CDecimal(valueSpecification) {
        return serialize(CDecimalModelSchema, valueSpecification);
    }
    visit_CString(valueSpecification) {
        return serialize(CStringModelSchema, valueSpecification);
    }
    visit_CBoolean(valueSpecification) {
        return serialize(CBooleanModelSchema, valueSpecification);
    }
    visit_CByteArray(valueSpecification) {
        return serialize(CByteArrayModelSchema, valueSpecification);
    }
    visit_CFloat(valueSpecification) {
        return serialize(CFloatModelSchema, valueSpecification);
    }
    visit_CDateTime(valueSpecification) {
        return serialize(CDateTimeModelSchema, valueSpecification);
    }
    visit_CStrictDate(valueSpecification) {
        return serialize(CStrictDateModelSchema, valueSpecification);
    }
    visit_CStrictTime(valueSpecification) {
        return serialize(CStrictTimeModelSchema, valueSpecification);
    }
    visit_CLatestDate(valueSpecification) {
        return serialize(CLatestDateModelSchema, valueSpecification);
    }
    visit_ClassInstance(valueSpecification) {
        return serialize(classInstanceModelSchema(this.plugins), valueSpecification);
    }
}
export function V1_deserializeValueSpecification(json, plugins) {
    switch (json._type) {
        case V1_ValueSpecificationType.APPLIED_FUNCTION:
            return deserialize(appliedFunctionModelSchema(plugins), json);
        case V1_ValueSpecificationType.APPLIED_PROPERTY:
            return deserialize(appliedPropertyModelSchema(plugins), json);
        case V1_ValueSpecificationType.VARIABLE:
            return deserialize(V1_variableModelSchema, json);
        case V1_ValueSpecificationType.LAMBDA:
            return deserialize(V1_lambdaModelSchema(plugins), json);
        case V1_ValueSpecificationType.KEY_EXPRESSION:
            return deserialize(keyExpressionModelSchema(plugins), json);
        case V1_ValueSpecificationType.COLLECTION:
            return deserialize(collectionModelSchema(plugins), json);
        case V1_ValueSpecificationType.ENUM_VALUE:
            return deserialize(enumValueModelSchema, json);
        // primitive values
        case V1_ValueSpecificationType.CBOOLEAN:
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CBooleanModelSchema, val));
        case V1_ValueSpecificationType.CBYTEARRAY: {
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CByteArrayModelSchema, val));
        }
        case V1_ValueSpecificationType.CDATETIME:
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CDateTimeModelSchema, val));
        case V1_ValueSpecificationType.CSTRICTTIME:
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CStrictTimeModelSchema, val));
        case V1_ValueSpecificationType.CDECIMAL:
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CDecimalModelSchema, val));
        case V1_ValueSpecificationType.CFLOAT:
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CFloatModelSchema, val));
        case V1_ValueSpecificationType.CINTEGER:
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CIntegerModelSchema, val));
        case V1_ValueSpecificationType.CLATESTDATE:
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CLatestDateModelSchema, val));
        case V1_ValueSpecificationType.CSTRICTDATE:
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CStrictDateModelSchema, val));
        case V1_ValueSpecificationType.CSTRING: {
            // This workaround is intended to handle an edge case where CString is sent with empty values
            // we will convert it to an empty string instead
            // See https://github.com/finos/legend-engine/pull/1076
            if (Array.isArray(json.values) &&
                !json.values.length &&
                isPlainObject(json.multiplicity) &&
                json.multiplicity.upperBound === 1) {
                const result = new V1_CString();
                result.value = '';
                return result;
            }
            return deserializePrimitiveValueSpecification(json, plugins, (val) => deserialize(CStringModelSchema, val));
        }
        // class instance
        case V1_ValueSpecificationType.CLASS_INSTANCE:
            return deserialize(classInstanceModelSchema(plugins), json);
        /**
         * NOTE: the following types are here for backward compatibility
         * as some of these are used to be value specifications, but now
         * transformed into class instances
         *
         * @backwardCompatibility
         */
        case V1_ClassInstanceType.PAIR:
        case V1_ClassInstanceType.AGGREGATE_VALUE:
        case V1_ClassInstanceType.EXECUTION_CONTEXT_INSTANCE:
        case V1_ClassInstanceType.PATH:
        case V1_ClassInstanceType.ROOT_GRAPH_FETCH_TREE:
        case V1_ClassInstanceType.PURE_LIST:
        case V1_ClassInstanceType.RUNTIME_INSTANCE:
        case V1_ClassInstanceType.SERIALIZATION_CONFIG:
        case V1_ClassInstanceType.TDS_AGGREGATE_VALUE:
        case V1_ClassInstanceType.TDS_COLUMN_INFORMATION:
        case V1_ClassInstanceType.TDS_OLAP_AGGREGATION:
        case V1_ClassInstanceType.TDS_OLAP_RANK:
        case V1_ClassInstanceType.TDS_SORT_INFORMATION:
            return deserialize(classInstanceModelSchema(plugins), {
                _type: V1_ValueSpecificationType.CLASS_INSTANCE,
                type: json._type,
                value: json,
            });
        // packageable element pointer
        case V1_ValueSpecificationType.HACKED_CLASS: // deprecated
            return deserializeHackedClass(json);
        case V1_ValueSpecificationType.UNIT_TYPE: // deprecated
        case V1_ValueSpecificationType.HACKED_UNIT: // deprecated
            return deserializeHackedUnit(json);
        case V1_ValueSpecificationType.PRIMITIVE_TYPE: // deprecated
        case V1_ValueSpecificationType.ENUM: // deprecated
        case V1_ValueSpecificationType.CLASS: // deprecated
        case V1_ValueSpecificationType.MAPPING_INSTANCE: // deprecated
        case V1_ValueSpecificationType.PACKAGEABLE_ELEMENT_PTR:
            return deserialize(V1_packageableElementPtrSchema(), json);
        case V1_ValueSpecificationType.GENERIC_TYPE_INSTANCE:
            return deserialize(genericTypeInstanceSchema(plugins), json);
        default:
            throw new UnsupportedOperationError(`Can't deserialize value specification of type '${json._type}'`);
    }
}
export function V1_serializeValueSpecification(protocol, plugins) {
    return protocol.accept_ValueSpecificationVisitor(new V1_ValueSpecificationSerializer(plugins));
}
//# sourceMappingURL=V1_ValueSpecificationSerializer.js.map