"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.decode = decode;
exports.encode = encode;
exports.encodeOptional = encodeOptional;
exports.decodeOptional = decodeOptional;
exports.encodeOptionalSingle = encodeOptionalSingle;
exports.decodeOptionalSingle = decodeOptionalSingle;
exports.decodeOptionalSinglePayload = decodeOptionalSinglePayload;
exports.encodeToPayload = encodeToPayload;
exports.decodeArrayFromPayloads = decodeArrayFromPayloads;
exports.decodeFromPayloadsAtIndex = decodeFromPayloadsAtIndex;
exports.decodeOptionalFailureToOptionalError = decodeOptionalFailureToOptionalError;
exports.decodeOptionalMap = decodeOptionalMap;
exports.encodeToPayloads = encodeToPayloads;
exports.decodeMapFromPayloads = decodeMapFromPayloads;
exports.encodeMap = encodeMap;
exports.encodeMapToPayloads = encodeMapToPayloads;
exports.encodeErrorToFailure = encodeErrorToFailure;
exports.encodeFailure = encodeFailure;
exports.decodeFailure = decodeFailure;
exports.encodeOptionalFailure = encodeOptionalFailure;
exports.decodeOptionalFailure = decodeOptionalFailure;
exports.noopEncodeMap = noopEncodeMap;
exports.noopEncodeSearchAttrs = noopEncodeSearchAttrs;
exports.noopDecodeMap = noopDecodeMap;
exports.encodeUserMetadata = encodeUserMetadata;
exports.decodeUserMetadata = decodeUserMetadata;
const payload_converter_1 = require("../converter/payload-converter");
const errors_1 = require("../errors");
/**
 * Decode through each codec, starting with the last codec.
 */
async function decode(codecs, payloads) {
    for (let i = codecs.length - 1; i >= 0; i--) {
        payloads = await codecs[i].decode(payloads);
    }
    return payloads;
}
/**
 * Encode through each codec, starting with the first codec.
 */
async function encode(codecs, payloads) {
    for (let i = 0; i < codecs.length; i++) {
        payloads = await codecs[i].encode(payloads);
    }
    return payloads;
}
/** Run {@link PayloadCodec.encode} on `payloads` */
async function encodeOptional(codecs, payloads) {
    if (payloads == null)
        return payloads;
    return await encode(codecs, payloads);
}
/** Run {@link PayloadCodec.decode} on `payloads` */
async function decodeOptional(codecs, payloads) {
    if (payloads == null)
        return payloads;
    return await decode(codecs, payloads);
}
async function encodeSingle(codecs, payload) {
    const encodedPayloads = await encode(codecs, [payload]);
    return encodedPayloads[0];
}
async function decodeSingle(codecs, payload) {
    const [decodedPayload] = await decode(codecs, [payload]);
    return decodedPayload;
}
/** Run {@link PayloadCodec.encode} on a single Payload */
async function encodeOptionalSingle(codecs, payload) {
    if (payload == null)
        return payload;
    return await encodeSingle(codecs, payload);
}
/** Run {@link PayloadCodec.decode} on a single Payload */
async function decodeOptionalSingle(codecs, payload) {
    if (payload == null)
        return payload;
    return await decodeSingle(codecs, payload);
}
/** Run {@link PayloadCodec.decode} and convert from a single Payload */
async function decodeOptionalSinglePayload(dataConverter, payload) {
    const { payloadConverter, payloadCodecs } = dataConverter;
    const decoded = await decodeOptionalSingle(payloadCodecs, payload);
    if (decoded == null)
        return decoded;
    return payloadConverter.fromPayload(decoded);
}
/**
 * Run {@link PayloadConverter.toPayload} on value, and then encode it.
 */
async function encodeToPayload(converter, value) {
    const { payloadConverter, payloadCodecs } = converter;
    return await encodeSingle(payloadCodecs, payloadConverter.toPayload(value));
}
/**
 * Decode `payloads` and then return {@link arrayFromPayloads}`.
 */
async function decodeArrayFromPayloads(converter, payloads) {
    const { payloadConverter, payloadCodecs } = converter;
    return (0, payload_converter_1.arrayFromPayloads)(payloadConverter, await decodeOptional(payloadCodecs, payloads));
}
/**
 * Decode `payloads` and then return {@link fromPayloadsAtIndex}.
 */
async function decodeFromPayloadsAtIndex(converter, index, payloads) {
    const { payloadConverter, payloadCodecs } = converter;
    return await (0, payload_converter_1.fromPayloadsAtIndex)(payloadConverter, index, await decodeOptional(payloadCodecs, payloads));
}
/**
 * Run {@link decodeFailure} and then return {@link failureToError}.
 */
async function decodeOptionalFailureToOptionalError(converter, failure) {
    const { failureConverter, payloadConverter, payloadCodecs } = converter;
    return failure
        ? failureConverter.failureToError(await decodeFailure(payloadCodecs, failure), payloadConverter)
        : undefined;
}
async function decodeOptionalMap(codecs, payloads) {
    if (payloads == null)
        return payloads;
    return Object.fromEntries(await Promise.all(Object.entries(payloads).map(async ([k, v]) => [k, (await decode(codecs, [v]))[0]])));
}
/**
 * Run {@link PayloadConverter.toPayload} on values, and then encode them.
 */
async function encodeToPayloads(converter, ...values) {
    const { payloadConverter, payloadCodecs } = converter;
    if (values.length === 0) {
        return undefined;
    }
    const payloads = (0, payload_converter_1.toPayloads)(payloadConverter, ...values);
    return payloads ? await encode(payloadCodecs, payloads) : undefined;
}
/**
 * Run {@link PayloadCodec.decode} and then {@link PayloadConverter.fromPayload} on values in `map`.
 */
async function decodeMapFromPayloads(converter, map) {
    if (!map)
        return undefined;
    const { payloadConverter, payloadCodecs } = converter;
    return Object.fromEntries(await Promise.all(Object.entries(map).map(async ([k, payload]) => {
        const [decodedPayload] = await decode(payloadCodecs, [payload]);
        const value = payloadConverter.fromPayload(decodedPayload);
        return [k, value];
    })));
}
/** Run {@link PayloadCodec.encode} on all values in `map` */
async function encodeMap(codecs, map) {
    if (map === null)
        return null;
    if (map === undefined)
        return undefined;
    return Object.fromEntries(await Promise.all(Object.entries(map).map(async ([k, payload]) => {
        return [k, await encodeSingle(codecs, payload)];
    })));
}
/**
 * Run {@link PayloadConverter.toPayload} and then {@link PayloadCodec.encode} on values in `map`.
 */
async function encodeMapToPayloads(converter, map) {
    const { payloadConverter, payloadCodecs } = converter;
    return Object.fromEntries(await Promise.all(Object.entries(map).map(async ([k, v]) => {
        const payload = payloadConverter.toPayload(v);
        if (payload === undefined)
            throw new errors_1.PayloadConverterError(`Failed to encode entry: ${k}: ${v}`);
        const [encodedPayload] = await encode(payloadCodecs, [payload]);
        return [k, encodedPayload];
    })));
}
/**
 * Run {@link errorToFailure} on `error`, and then {@link encodeFailure}.
 */
async function encodeErrorToFailure(dataConverter, error) {
    const { failureConverter, payloadConverter, payloadCodecs } = dataConverter;
    return await encodeFailure(payloadCodecs, failureConverter.errorToFailure(error, payloadConverter));
}
/**
 * Return a new {@link ProtoFailure} with `codec.encode()` run on all the {@link Payload}s.
 */
async function encodeFailure(codecs, failure) {
    return {
        ...failure,
        encodedAttributes: failure.encodedAttributes ? (await encode(codecs, [failure.encodedAttributes]))[0] : undefined,
        cause: failure.cause ? await encodeFailure(codecs, failure.cause) : null,
        applicationFailureInfo: failure.applicationFailureInfo
            ? {
                ...failure.applicationFailureInfo,
                details: failure.applicationFailureInfo.details
                    ? {
                        payloads: await encode(codecs, failure.applicationFailureInfo.details.payloads ?? []),
                    }
                    : undefined,
            }
            : undefined,
        timeoutFailureInfo: failure.timeoutFailureInfo
            ? {
                ...failure.timeoutFailureInfo,
                lastHeartbeatDetails: failure.timeoutFailureInfo.lastHeartbeatDetails
                    ? {
                        payloads: await encode(codecs, failure.timeoutFailureInfo.lastHeartbeatDetails.payloads ?? []),
                    }
                    : undefined,
            }
            : undefined,
        canceledFailureInfo: failure.canceledFailureInfo
            ? {
                ...failure.canceledFailureInfo,
                details: failure.canceledFailureInfo.details
                    ? {
                        payloads: await encode(codecs, failure.canceledFailureInfo.details.payloads ?? []),
                    }
                    : undefined,
            }
            : undefined,
        resetWorkflowFailureInfo: failure.resetWorkflowFailureInfo
            ? {
                ...failure.resetWorkflowFailureInfo,
                lastHeartbeatDetails: failure.resetWorkflowFailureInfo.lastHeartbeatDetails
                    ? {
                        payloads: await encode(codecs, failure.resetWorkflowFailureInfo.lastHeartbeatDetails.payloads ?? []),
                    }
                    : undefined,
            }
            : undefined,
    };
}
/**
 * Return a new {@link ProtoFailure} with `codec.decode()` run on all the {@link Payload}s.
 */
async function decodeFailure(codecs, failure) {
    return {
        ...failure,
        encodedAttributes: failure.encodedAttributes ? (await decode(codecs, [failure.encodedAttributes]))[0] : undefined,
        cause: failure.cause ? await decodeFailure(codecs, failure.cause) : null,
        applicationFailureInfo: failure.applicationFailureInfo
            ? {
                ...failure.applicationFailureInfo,
                details: failure.applicationFailureInfo.details
                    ? {
                        payloads: await decode(codecs, failure.applicationFailureInfo.details.payloads ?? []),
                    }
                    : undefined,
            }
            : undefined,
        timeoutFailureInfo: failure.timeoutFailureInfo
            ? {
                ...failure.timeoutFailureInfo,
                lastHeartbeatDetails: failure.timeoutFailureInfo.lastHeartbeatDetails
                    ? {
                        payloads: await decode(codecs, failure.timeoutFailureInfo.lastHeartbeatDetails.payloads ?? []),
                    }
                    : undefined,
            }
            : undefined,
        canceledFailureInfo: failure.canceledFailureInfo
            ? {
                ...failure.canceledFailureInfo,
                details: failure.canceledFailureInfo.details
                    ? {
                        payloads: await decode(codecs, failure.canceledFailureInfo.details.payloads ?? []),
                    }
                    : undefined,
            }
            : undefined,
        resetWorkflowFailureInfo: failure.resetWorkflowFailureInfo
            ? {
                ...failure.resetWorkflowFailureInfo,
                lastHeartbeatDetails: failure.resetWorkflowFailureInfo.lastHeartbeatDetails
                    ? {
                        payloads: await decode(codecs, failure.resetWorkflowFailureInfo.lastHeartbeatDetails.payloads ?? []),
                    }
                    : undefined,
            }
            : undefined,
    };
}
/**
 * Return a new {@link ProtoFailure} with `codec.encode()` run on all the {@link Payload}s.
 */
async function encodeOptionalFailure(codecs, failure) {
    if (failure == null)
        return failure;
    return await encodeFailure(codecs, failure);
}
/**
 * Return a new {@link ProtoFailure} with `codec.encode()` run on all the {@link Payload}s.
 */
async function decodeOptionalFailure(codecs, failure) {
    if (failure == null)
        return failure;
    return await decodeFailure(codecs, failure);
}
/**
 * Mark all values in the map as encoded.
 * Use this for headers, which we don't encode.
 */
function noopEncodeMap(map) {
    return map;
}
function noopEncodeSearchAttrs(attrs) {
    if (!attrs) {
        return attrs;
    }
    return {
        indexedFields: noopEncodeMap(attrs.indexedFields),
    };
}
/**
 * Mark all values in the map as decoded.
 * Use this for headers, which we don't encode.
 */
function noopDecodeMap(map) {
    return map;
}
async function encodeUserMetadata(dataConverter, staticSummary, staticDetails) {
    if (staticSummary == null && staticDetails == null)
        return undefined;
    const { payloadConverter, payloadCodecs } = dataConverter;
    const summary = await encodeOptionalSingle(payloadCodecs, (0, payload_converter_1.convertOptionalToPayload)(payloadConverter, staticSummary));
    const details = await encodeOptionalSingle(payloadCodecs, (0, payload_converter_1.convertOptionalToPayload)(payloadConverter, staticDetails));
    if (summary == null && details == null)
        return undefined;
    return { summary, details };
}
async function decodeUserMetadata(dataConverter, metadata) {
    const res = { staticSummary: undefined, staticDetails: undefined };
    if (metadata == null)
        return res;
    const staticSummary = (await decodeOptionalSinglePayload(dataConverter, metadata.summary)) ?? undefined;
    const staticDetails = (await decodeOptionalSinglePayload(dataConverter, metadata.details)) ?? undefined;
    return { staticSummary, staticDetails };
}
//# sourceMappingURL=codec-helpers.js.map