"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.historyFromJSON = historyFromJSON;
exports.historyToJSON = historyToJSON;
exports.fixBuffers = fixBuffers;
exports.payloadToJSON = payloadToJSON;
exports.JSONToPayload = JSONToPayload;
const proto3_json_serializer_1 = require("proto3-json-serializer");
const proto = __importStar(require("@temporalio/proto"));
const patch_protobuf_root_1 = require("@temporalio/proto/lib/patch-protobuf-root");
// Cast to any because the generated proto module types are missing the lookupType method
const patched = (0, patch_protobuf_root_1.patchProtobufRoot)(proto);
const historyType = patched.lookupType('temporal.api.history.v1.History');
const payloadType = patched.lookupType('temporal.api.common.v1.Payload');
/**
 * Convert a proto JSON representation of History to a valid History object
 */
function historyFromJSON(history) {
    function pascalCaseToConstantCase(s) {
        return s.replace(/[^\b][A-Z]/g, (m) => `${m[0]}_${m[1]}`).toUpperCase();
    }
    function fixEnumValue(obj, attr, prefix) {
        return (obj[attr] && {
            [attr]: obj[attr].startsWith(prefix) ? obj[attr] : `${prefix}_${pascalCaseToConstantCase(obj[attr])}`,
        });
    }
    // fromProto3JSON doesn't allow null values on 'bytes' fields. This turns out to be a problem for payloads.
    // Recursively descend on objects and array, and fix in-place any payload that has a null data field
    function fixPayloads(e) {
        function isPayload(p) {
            return p && typeof p === 'object' && 'metadata' in p && 'data' in p;
        }
        if (e && typeof e === 'object') {
            if (isPayload(e)) {
                if (e.data === null) {
                    const { data: _data, ...rest } = e;
                    return rest;
                }
                return e;
            }
            if (Array.isArray(e))
                return e.map(fixPayloads);
            return Object.fromEntries(Object.entries(e).map(([k, v]) => [k, fixPayloads(v)]));
        }
        return e;
    }
    function fixHistoryEvent(e) {
        const type = Object.keys(e).find((k) => k.endsWith('EventAttributes'));
        if (!type) {
            throw new TypeError(`Missing attributes in history event: ${JSON.stringify(e)}`);
        }
        // Fix payloads with null data
        e = fixPayloads(e);
        return {
            ...e,
            ...fixEnumValue(e, 'eventType', 'EVENT_TYPE'),
            [type]: {
                ...e[type],
                ...(e[type].taskQueue && {
                    taskQueue: { ...e[type].taskQueue, ...fixEnumValue(e[type].taskQueue, 'kind', 'TASK_QUEUE_KIND') },
                }),
                ...fixEnumValue(e[type], 'parentClosePolicy', 'PARENT_CLOSE_POLICY'),
                ...fixEnumValue(e[type], 'workflowIdReusePolicy', 'WORKFLOW_ID_REUSE_POLICY'),
                ...fixEnumValue(e[type], 'initiator', 'CONTINUE_AS_NEW_INITIATOR'),
                ...fixEnumValue(e[type], 'retryState', 'RETRY_STATE'),
                ...(e[type].childWorkflowExecutionFailureInfo && {
                    childWorkflowExecutionFailureInfo: {
                        ...e[type].childWorkflowExecutionFailureInfo,
                        ...fixEnumValue(e[type].childWorkflowExecutionFailureInfo, 'retryState', 'RETRY_STATE'),
                    },
                }),
            },
        };
    }
    function fixHistory(h) {
        return {
            events: h.events.map(fixHistoryEvent),
        };
    }
    if (typeof history !== 'object' || history == null || !Array.isArray(history.events)) {
        throw new TypeError('Invalid history, expected an object with an array of events');
    }
    const loaded = (0, proto3_json_serializer_1.fromProto3JSON)(historyType, fixHistory(history));
    if (loaded === null) {
        throw new TypeError('Invalid history');
    }
    return loaded;
}
/**
 * Convert an History object, e.g. as returned by `WorkflowClient.list().withHistory()`, to a JSON
 * string that adheres to the same norm as JSON history files produced by other Temporal tools.
 */
function historyToJSON(history) {
    const protoJson = (0, proto3_json_serializer_1.toProto3JSON)(proto.temporal.api.history.v1.History.fromObject(history));
    return JSON.stringify(fixBuffers(protoJson), null, 2);
}
/**
 * toProto3JSON doesn't correctly handle some of our "bytes" fields, passing them untouched to the
 * output, after which JSON.stringify() would convert them to an array of numbers. As a workaround,
 * recursively walk the object and convert all Buffer instances to base64 strings. Note this only
 * works on proto3-json-serializer v2.0.0. v2.0.2 throws an error before we even get the chance
 * to fix the buffers. See https://github.com/googleapis/proto3-json-serializer-nodejs/issues/103.
 */
function fixBuffers(e) {
    if (e && typeof e === 'object') {
        if (e instanceof Buffer)
            return e.toString('base64');
        if (e instanceof Uint8Array)
            return Buffer.from(e).toString('base64');
        if (Array.isArray(e))
            return e.map(fixBuffers);
        return Object.fromEntries(Object.entries(e).map(([k, v]) => [k, fixBuffers(v)]));
    }
    return e;
}
/**
 * Convert from protobuf payload to JSON
 */
function payloadToJSON(payload) {
    return fixBuffers((0, proto3_json_serializer_1.toProto3JSON)(patched.temporal.api.common.v1.Payload.create(payload)));
}
/**
 * Convert from JSON to protobuf payload
 */
function JSONToPayload(json) {
    const loaded = (0, proto3_json_serializer_1.fromProto3JSON)(payloadType, json);
    if (loaded === null) {
        throw new TypeError('Invalid payload');
    }
    return loaded;
}
//# sourceMappingURL=proto-utils.js.map