/**
 * 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, raw, serialize, deserialize, custom, alias, optional, list, } from 'serializr';
import { usingConstantValueSchema, UnsupportedOperationError, usingModelSchema, customList, optionalCustomList, optionalCustomListWithSchema, isString, } from '@finos/legend-shared';
import { V1_RawLambda } from '../../../model/rawValueSpecification/V1_RawLambda.js';
import { V1_RawGenericType, V1_RawRawType, V1_RawRelationType, V1_RawRelationColumn, V1_RawVariable, } from '../../../model/rawValueSpecification/V1_RawVariable.js';
import { V1_multiplicityModelSchema } from '../../../transformation/pureProtocol/serializationHelpers/V1_CoreSerializationHelper.js';
import { V1_RawBaseExecutionContext } from '../../../model/rawValueSpecification/V1_RawExecutionContext.js';
import { V1_RawPrimitiveInstanceValue } from '../../../model/rawValueSpecification/V1_RawPrimitiveInstanceValue.js';
import { CORE_PURE_PATH, PRIMITIVE_TYPE, } from '../../../../../../../graph/MetaModelConst.js';
import { V1_Type_Type } from './V1_TypeSerializationHelper.js';
import { V1_Multiplicity } from '../../../model/packageableElements/domain/V1_Multiplicity.js';
import { matchFunctionName } from '../../../../../../../graph/MetaModelUtils.js';
import { V1_deserializeValueSpecification, V1_serializeValueSpecification, } from './V1_ValueSpecificationSerializer.js';
var V1_RawExecutionContextType;
(function (V1_RawExecutionContextType) {
    V1_RawExecutionContextType["BASE_EXECUTION_CONTEXT"] = "BaseExecutionContext";
})(V1_RawExecutionContextType || (V1_RawExecutionContextType = {}));
export var V1_RawValueSpecificationType;
(function (V1_RawValueSpecificationType) {
    V1_RawValueSpecificationType["LAMBDA"] = "lambda";
    V1_RawValueSpecificationType["VARIABLE"] = "var";
    V1_RawValueSpecificationType["CINTEGER"] = "integer";
    V1_RawValueSpecificationType["CDECIMAL"] = "decimal";
    V1_RawValueSpecificationType["CSTRING"] = "string";
    V1_RawValueSpecificationType["CBOOLEAN"] = "boolean";
    V1_RawValueSpecificationType["CFLOAT"] = "float";
    V1_RawValueSpecificationType["CDATETIME"] = "dateTime";
    V1_RawValueSpecificationType["CSTRICTDATE"] = "strictDate";
    V1_RawValueSpecificationType["CSTRICTTIME"] = "strictTime";
    V1_RawValueSpecificationType["CLATESTDATE"] = "latestDate";
    V1_RawValueSpecificationType["CDATE"] = "date";
})(V1_RawValueSpecificationType || (V1_RawValueSpecificationType = {}));
const rawRawTypeSchemaModel = createModelSchema(V1_RawRawType, {
    _type: usingConstantValueSchema(V1_Type_Type.PACKAGEABLE_TYPE),
    fullPath: primitive(),
});
function serializeRawType(val) {
    if (val instanceof V1_RawRelationType) {
        return serialize(rawRelationTypeSchemaModel(), val);
    }
    return serialize(rawRawTypeSchemaModel, val);
}
function deserializeRawType(val) {
    if (val._type === V1_Type_Type.RELATION_TYPE) {
        return deserialize(rawRelationTypeSchemaModel(), val);
    }
    return deserialize(rawRawTypeSchemaModel, val);
}
function V1_RawGenericTypeSchemaModelInner() {
    return createModelSchema(V1_RawGenericType, {
        multiplicityArguments: customList((val) => serialize(V1_multiplicityModelSchema, val), (val) => deserialize(V1_multiplicityModelSchema, val), {
            INTERNAL__forceReturnEmptyInTest: true,
        }),
        rawType: custom((val) => serializeRawType(val), (val) => deserializeRawType(val)),
        typeArguments: optionalCustomList((value) => serialize(V1_RawGenericType, value), (value) => deserialize(V1_RawGenericType, value), {
            INTERNAL__forceReturnEmptyInTest: true,
        }),
        typeVariableValues: optionalCustomList((value) => V1_serializeValueSpecification(value, []), (value) => V1_deserializeValueSpecification(value, []), {
            INTERNAL__forceReturnEmptyInTest: true,
        }),
    });
}
function V1_rawRelationColumnModelSchema() {
    return createModelSchema(V1_RawRelationColumn, {
        name: primitive(),
        genericType: custom((val) => serialize(V1_RawGenericTypeSchemaModelInner(), val), (val) => deserialize(V1_RawGenericTypeSchemaModelInner(), val)),
        multiplicity: optional(usingModelSchema(V1_multiplicityModelSchema)),
    });
}
function rawRelationTypeSchemaModel() {
    return createModelSchema(V1_RawRelationType, {
        _type: usingConstantValueSchema(V1_Type_Type.RELATION_TYPE),
        columns: list(usingModelSchema(V1_rawRelationColumnModelSchema())),
    });
}
const V1_RawGenericTypeSchemaModel = createModelSchema(V1_RawGenericType, {
    multiplicityArguments: customList((val) => serialize(V1_multiplicityModelSchema, val), (val) => deserialize(V1_multiplicityModelSchema, val), {
        INTERNAL__forceReturnEmptyInTest: true,
    }),
    rawType: usingModelSchema(rawRawTypeSchemaModel),
    typeArguments: optionalCustomListWithSchema(V1_RawGenericTypeSchemaModelInner(), {
        INTERNAL__forceReturnEmptyInTest: true,
    }),
    typeVariableValues: optionalCustomList((value) => V1_serializeValueSpecification(value, []), (value) => V1_deserializeValueSpecification(value, []), {
        INTERNAL__forceReturnEmptyInTest: true,
    }),
});
const V1_deserializeRawGenericType = (val) => {
    let genericType;
    /** @backwardCompatibility */
    if (isString(val)) {
        genericType = new V1_RawGenericType();
        const packageableType = new V1_RawRawType();
        packageableType.fullPath = val;
        genericType.rawType = packageableType;
    }
    else {
        genericType = deserialize(V1_RawGenericTypeSchemaModel, val);
    }
    if (matchFunctionName(genericType.rawType.fullPath, CORE_PURE_PATH.TABULAR_RESULT) &&
        !genericType.multiplicityArguments.length &&
        !genericType.typeArguments.length) {
        genericType.multiplicityArguments = [new V1_Multiplicity(1, undefined)];
        const _anytype = new V1_RawRawType();
        _anytype.fullPath = CORE_PURE_PATH.ANY;
        const arGenType = new V1_RawGenericType();
        arGenType.rawType = _anytype;
        genericType.typeArguments = [arGenType];
    }
    return genericType;
};
export const V1_rawBaseExecutionContextModelSchema = createModelSchema(V1_RawBaseExecutionContext, {
    _type: usingConstantValueSchema(V1_RawExecutionContextType.BASE_EXECUTION_CONTEXT),
    queryTimeOutInSeconds: primitive(),
    enableConstraints: primitive(),
});
export const V1_rawLambdaModelSchema = createModelSchema(V1_RawLambda, {
    _type: usingConstantValueSchema(V1_RawValueSpecificationType.LAMBDA),
    body: raw(),
    parameters: raw(),
});
export const V1_rawVariableModelSchema = createModelSchema(V1_RawVariable, {
    _type: usingConstantValueSchema(V1_RawValueSpecificationType.VARIABLE),
    genericType: custom((val) => serialize(V1_RawGenericTypeSchemaModel, val), (val) => V1_deserializeRawGenericType(val), {
        beforeDeserialize: function (callback, jsonValue, jsonParentValue) {
            /** @backwardCompatibility */
            if (jsonParentValue.class !== undefined &&
                jsonParentValue.genericType === undefined) {
                callback(null, jsonParentValue.class);
            }
            else {
                callback(null, jsonValue);
            }
        },
    }),
    multiplicity: usingModelSchema(V1_multiplicityModelSchema),
    name: primitive(),
});
export const V1_rawPrimitiveInstanceValueSchema = createModelSchema(V1_RawPrimitiveInstanceValue, {
    type: alias('_type', custom((val) => {
        switch (val) {
            case PRIMITIVE_TYPE.INTEGER:
                return V1_RawValueSpecificationType.CINTEGER;
            case PRIMITIVE_TYPE.DECIMAL:
                return V1_RawValueSpecificationType.CDECIMAL;
            case PRIMITIVE_TYPE.STRING:
                return V1_RawValueSpecificationType.CSTRING;
            case PRIMITIVE_TYPE.BOOLEAN:
                return V1_RawValueSpecificationType.CBOOLEAN;
            case PRIMITIVE_TYPE.FLOAT:
                return V1_RawValueSpecificationType.CFLOAT;
            case PRIMITIVE_TYPE.DATETIME:
                return V1_RawValueSpecificationType.CDATETIME;
            case PRIMITIVE_TYPE.STRICTDATE:
                return V1_RawValueSpecificationType.CSTRICTDATE;
            case PRIMITIVE_TYPE.STRICTTIME:
                return V1_RawValueSpecificationType.CSTRICTTIME;
            case PRIMITIVE_TYPE.LATESTDATE:
                return V1_RawValueSpecificationType.CLATESTDATE;
            default:
                throw new UnsupportedOperationError(`Can't serialize raw instance value type '${val}'`);
        }
    }, (val) => {
        switch (val) {
            case V1_RawValueSpecificationType.CINTEGER:
                return PRIMITIVE_TYPE.INTEGER;
            case V1_RawValueSpecificationType.CDECIMAL:
                return PRIMITIVE_TYPE.DECIMAL;
            case V1_RawValueSpecificationType.CSTRING:
                return PRIMITIVE_TYPE.STRING;
            case V1_RawValueSpecificationType.CBOOLEAN:
                return PRIMITIVE_TYPE.BOOLEAN;
            case V1_RawValueSpecificationType.CFLOAT:
                return PRIMITIVE_TYPE.FLOAT;
            case V1_RawValueSpecificationType.CDATETIME:
                return PRIMITIVE_TYPE.DATETIME;
            case V1_RawValueSpecificationType.CSTRICTDATE:
                return PRIMITIVE_TYPE.STRICTDATE;
            case V1_RawValueSpecificationType.CSTRICTTIME:
                return PRIMITIVE_TYPE.STRICTTIME;
            case V1_RawValueSpecificationType.CLATESTDATE:
                return PRIMITIVE_TYPE.LATESTDATE;
            default:
                throw new UnsupportedOperationError(`Can't deserialize raw value instance value type '${val}'`);
        }
    })),
    value: optional(primitive()),
});
/** @backwardCompatibility */
const deserializePrimitiveInstanceValue = (json) => deserialize(V1_rawPrimitiveInstanceValueSchema, {
    ...json,
    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
    value: Array.isArray(json.values) && json.values.length === 1
        ? json.values[0]
        : json.value,
});
class V1_RawValueSpecificationSerializer {
    visit_Lambda(rawValueSpecification) {
        return serialize(V1_rawLambdaModelSchema, rawValueSpecification);
    }
    visit_Variable(rawValueSpecification) {
        return serialize(V1_rawVariableModelSchema, rawValueSpecification);
    }
    visit_PrimitiveInstanceValue(rawValueSpecification) {
        return serialize(V1_rawPrimitiveInstanceValueSchema, rawValueSpecification);
    }
}
export function V1_serializeRawValueSpecification(protocol) {
    return protocol.accept_RawValueSpecificationVisitor(new V1_RawValueSpecificationSerializer());
}
export function V1_deserializeRawValueSpecification(json) {
    switch (json._type) {
        case V1_RawValueSpecificationType.LAMBDA:
            return deserialize(V1_rawLambdaModelSchema, json);
        case V1_RawValueSpecificationType.VARIABLE:
            return deserialize(V1_rawVariableModelSchema, json);
        case V1_RawValueSpecificationType.CINTEGER:
        case V1_RawValueSpecificationType.CDECIMAL:
        case V1_RawValueSpecificationType.CSTRING:
        case V1_RawValueSpecificationType.CBOOLEAN:
        case V1_RawValueSpecificationType.CFLOAT:
        case V1_RawValueSpecificationType.CDATETIME:
        case V1_RawValueSpecificationType.CSTRICTDATE:
        case V1_RawValueSpecificationType.CSTRICTTIME:
        case V1_RawValueSpecificationType.CLATESTDATE:
            return deserializePrimitiveInstanceValue(json);
        default:
            throw new UnsupportedOperationError(`Can't deserialize raw value specification of type '${json._type}'`);
    }
}
export function V1_deserializeRawValueSpecificationType(type) {
    switch (type) {
        case PRIMITIVE_TYPE.INTEGER:
            return V1_RawValueSpecificationType.CINTEGER;
        case PRIMITIVE_TYPE.DECIMAL:
            return V1_RawValueSpecificationType.CDECIMAL;
        case PRIMITIVE_TYPE.STRING:
            return V1_RawValueSpecificationType.CSTRING;
        case PRIMITIVE_TYPE.BOOLEAN:
            return V1_RawValueSpecificationType.CBOOLEAN;
        case PRIMITIVE_TYPE.FLOAT:
            return V1_RawValueSpecificationType.CFLOAT;
        case PRIMITIVE_TYPE.DATE:
        case PRIMITIVE_TYPE.DATETIME:
            return V1_RawValueSpecificationType.CDATETIME;
        case PRIMITIVE_TYPE.STRICTDATE:
            return V1_RawValueSpecificationType.CSTRICTDATE;
        case PRIMITIVE_TYPE.STRICTTIME:
            return V1_RawValueSpecificationType.CSTRICTTIME;
        case PRIMITIVE_TYPE.LATESTDATE:
            return V1_RawValueSpecificationType.CLATESTDATE;
        default:
            throw new UnsupportedOperationError(`Can't serialize raw instance value type '${type}'`);
    }
}
//# sourceMappingURL=V1_RawValueSpecificationSerializationHelper.js.map