import { RunnableBinding, RunnablePassthrough, RunnableSequence, _coerceToRunnable, } from "@langchain/core/runnables";
import { CONFIG_KEY_READ } from "../constants.js";
import { ChannelWrite } from "./write.js";
import { RunnableCallable } from "../utils.js";
export class ChannelRead extends RunnableCallable {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    constructor(channel, 
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    mapper, fresh = false) {
        super({
            func: (_, config) => ChannelRead.doRead(config, this.channel, this.fresh, this.mapper),
        });
        Object.defineProperty(this, "lc_graph_name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: "ChannelRead"
        });
        Object.defineProperty(this, "channel", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "fresh", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: false
        });
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        Object.defineProperty(this, "mapper", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        this.fresh = fresh;
        this.mapper = mapper;
        this.channel = channel;
        this.name = Array.isArray(channel)
            ? `ChannelRead<${channel.join(",")}>`
            : `ChannelRead<${channel}>`;
    }
    static doRead(config, channel, fresh, mapper) {
        const read = config.configurable?.[CONFIG_KEY_READ];
        if (!read) {
            throw new Error(`Runnable ${this} is not configured with a read function. Make sure to call in the context of a Pregel process`);
        }
        if (mapper) {
            return mapper(read(channel, fresh));
        }
        else {
            return read(channel, fresh);
        }
    }
}
const defaultRunnableBound = 
/* #__PURE__ */ new RunnablePassthrough();
export class PregelNode extends RunnableBinding {
    constructor(fields) {
        const { channels, triggers, mapper, writers, bound, kwargs } = fields;
        const mergedTags = [
            ...(fields.config?.tags ? fields.config.tags : []),
            ...(fields.tags ? fields.tags : []),
        ];
        super({
            ...fields,
            bound: fields.bound ??
                defaultRunnableBound,
            config: {
                ...(fields.config ? fields.config : {}),
                tags: mergedTags,
            },
        });
        Object.defineProperty(this, "lc_graph_name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: "PregelNode"
        });
        Object.defineProperty(this, "channels", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "triggers", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: []
        });
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        Object.defineProperty(this, "mapper", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "writers", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: []
        });
        Object.defineProperty(this, "bound", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: defaultRunnableBound
        });
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        Object.defineProperty(this, "kwargs", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: {}
        });
        this.channels = channels;
        this.triggers = triggers;
        this.mapper = mapper;
        this.writers = writers ?? this.writers;
        this.bound = bound ?? this.bound;
        this.kwargs = kwargs ?? this.kwargs;
    }
    getWriters() {
        const newWriters = [...this.writers];
        while (newWriters.length > 1 &&
            // eslint-disable-next-line no-instanceof/no-instanceof
            newWriters[newWriters.length - 1] instanceof ChannelWrite &&
            // eslint-disable-next-line no-instanceof/no-instanceof
            newWriters[newWriters.length - 2] instanceof ChannelWrite) {
            // we can combine writes if they are consecutive
            newWriters[newWriters.length - 2].writes.push(...newWriters[newWriters.length - 1].writes);
            newWriters.pop();
        }
        return newWriters;
    }
    getNode() {
        const writers = this.getWriters();
        if (this.bound === defaultRunnableBound && writers.length === 0) {
            return undefined;
        }
        else if (this.bound === defaultRunnableBound && writers.length === 1) {
            return writers[0];
        }
        else if (this.bound === defaultRunnableBound) {
            return new RunnableSequence({
                first: writers[0],
                middle: writers.slice(1, writers.length - 1),
                last: writers[writers.length - 1],
            });
        }
        else if (writers.length > 0) {
            return new RunnableSequence({
                first: this.bound,
                middle: writers.slice(0, writers.length - 1),
                last: writers[writers.length - 1],
            });
        }
        else {
            return this.bound;
        }
    }
    join(channels) {
        if (!Array.isArray(channels)) {
            throw new Error("channels must be a list");
        }
        if (typeof this.channels !== "object") {
            throw new Error("all channels must be named when using .join()");
        }
        return new PregelNode({
            channels: {
                ...this.channels,
                ...Object.fromEntries(channels.map((chan) => [chan, chan])),
            },
            triggers: this.triggers,
            mapper: this.mapper,
            writers: this.writers,
            bound: this.bound,
            kwargs: this.kwargs,
            config: this.config,
        });
    }
    pipe(coerceable) {
        if (ChannelWrite.isWriter(coerceable)) {
            return new PregelNode({
                channels: this.channels,
                triggers: this.triggers,
                mapper: this.mapper,
                writers: [...this.writers, coerceable],
                bound: this.bound,
                config: this.config,
                kwargs: this.kwargs,
            });
        }
        else if (this.bound === defaultRunnableBound) {
            return new PregelNode({
                channels: this.channels,
                triggers: this.triggers,
                mapper: this.mapper,
                writers: this.writers,
                bound: _coerceToRunnable(coerceable),
                config: this.config,
                kwargs: this.kwargs,
            });
        }
        else {
            return new PregelNode({
                channels: this.channels,
                triggers: this.triggers,
                mapper: this.mapper,
                writers: this.writers,
                bound: this.bound.pipe(coerceable),
                config: this.config,
                kwargs: this.kwargs,
            });
        }
    }
}
