"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsonPlusSerializer = void 0;
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-instanceof/no-instanceof */
const load_1 = require("@langchain/core/load");
const index_js_1 = require("./utils/fast-safe-stringify/index.cjs");
function isLangChainSerializedObject(value) {
    return (value !== null &&
        value.lc === 1 &&
        value.type === "constructor" &&
        Array.isArray(value.id));
}
/**
 * The replacer in stringify does not allow delegation to built-in LangChain
 * serialization methods, and instead immediately calls `.toJSON()` and
 * continues to stringify subfields.
 *
 * We therefore must start from the most nested elements in the input and
 * deserialize upwards rather than top-down.
 */
async function _reviver(value) {
    if (value && typeof value === "object") {
        if (Array.isArray(value)) {
            const revivedArray = await Promise.all(value.map((item) => _reviver(item)));
            return revivedArray;
        }
        else {
            const revivedObj = {};
            for (const [k, v] of Object.entries(value)) {
                revivedObj[k] = await _reviver(v);
            }
            if (revivedObj.lc === 2 && revivedObj.type === "undefined") {
                return undefined;
            }
            else if (revivedObj.lc === 2 &&
                revivedObj.type === "constructor" &&
                Array.isArray(revivedObj.id)) {
                try {
                    const constructorName = revivedObj.id[revivedObj.id.length - 1];
                    let constructor;
                    switch (constructorName) {
                        case "Set":
                            constructor = Set;
                            break;
                        case "Map":
                            constructor = Map;
                            break;
                        case "RegExp":
                            constructor = RegExp;
                            break;
                        case "Error":
                            constructor = Error;
                            break;
                        default:
                            return revivedObj;
                    }
                    if (revivedObj.method) {
                        return constructor[revivedObj.method](...(revivedObj.args || []));
                    }
                    else {
                        return new constructor(...(revivedObj.args || []));
                    }
                }
                catch (error) {
                    return revivedObj;
                }
            }
            else if (isLangChainSerializedObject(revivedObj)) {
                return (0, load_1.load)(JSON.stringify(revivedObj));
            }
            return revivedObj;
        }
    }
    return value;
}
function _encodeConstructorArgs(
// eslint-disable-next-line @typescript-eslint/ban-types
constructor, method, args, kwargs) {
    return {
        lc: 2,
        type: "constructor",
        id: [constructor.name],
        method: method ?? null,
        args: args ?? [],
        kwargs: kwargs ?? {},
    };
}
function _default(obj) {
    if (obj === undefined) {
        return {
            lc: 2,
            type: "undefined",
        };
    }
    else if (obj instanceof Set || obj instanceof Map) {
        return _encodeConstructorArgs(obj.constructor, undefined, [
            Array.from(obj),
        ]);
    }
    else if (obj instanceof RegExp) {
        return _encodeConstructorArgs(RegExp, undefined, [obj.source, obj.flags]);
    }
    else if (obj instanceof Error) {
        return _encodeConstructorArgs(obj.constructor, undefined, [obj.message]);
        // TODO: Remove special case
    }
    else if (obj?.lg_name === "Send") {
        return {
            node: obj.node,
            args: obj.args,
        };
    }
    else {
        return obj;
    }
}
class JsonPlusSerializer {
    _dumps(obj) {
        const encoder = new TextEncoder();
        return encoder.encode((0, index_js_1.stringify)(obj, (_, value) => {
            return _default(value);
        }));
    }
    dumpsTyped(obj) {
        if (obj instanceof Uint8Array) {
            return ["bytes", obj];
        }
        else {
            return ["json", this._dumps(obj)];
        }
    }
    async _loads(data) {
        const parsed = JSON.parse(data);
        return _reviver(parsed);
    }
    async loadsTyped(type, data) {
        if (type === "bytes") {
            return typeof data === "string" ? new TextEncoder().encode(data) : data;
        }
        else if (type === "json") {
            return this._loads(typeof data === "string" ? data : new TextDecoder().decode(data));
        }
        else {
            throw new Error(`Unknown serialization type: ${type}`);
        }
    }
}
exports.JsonPlusSerializer = JsonPlusSerializer;
//# sourceMappingURL=jsonplus.js.map