import { _getOverwriteValue, _isOverwriteValue } from "../constants.js";
import { EmptyChannelError, InvalidUpdateError } from "../errors.js";
import { BaseChannel } from "./base.js";
import { isDeltaSnapshot } from "@langchain/langgraph-checkpoint";
//#region src/channels/delta.ts
const isDeltaChannel = (value) => {
	return value != null && value.lc_graph_name === "DeltaChannel";
};
/**
* Reducer channel that stores only a sentinel in checkpoint blobs and
* reconstructs state by replaying ancestor writes through the reducer.
*
* `DeltaChannel` avoids re-serializing the full accumulated value at every
* step. Instead of writing the value into `channel_values`, the channel is
* omitted entirely and its state is reconstructed on read by walking the
* ancestor chain and replaying the per-step writes through the reducer (see
* {@link BaseCheckpointSaver.getDeltaChannelHistory}).
*
* Snapshot cadence is driven by two counters: a per-channel update count and
* the total supersteps since the last snapshot. A full {@link DeltaSnapshot}
* blob is written when EITHER the update count reaches `snapshotFrequency` OR
* the supersteps count reaches the system-wide
* `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT` bound (default 5000), bounding replay
* depth even for channels that stop receiving writes.
*
* @remarks Beta. The API and on-disk representation may change in future
* releases. Threads written with `DeltaChannel` today are expected to remain
* readable, but the surrounding contract (`getDeltaChannelHistory`, the
* `DeltaSnapshot` blob shape, the `counters_since_delta_snapshot` metadata
* field) is not yet stable.
*
* @example
* ```typescript
* import { Annotation } from "@langchain/langgraph";
* import { DeltaChannel, messagesDeltaReducer } from "@langchain/langgraph";
*
* const State = Annotation.Root({
*   messages: Annotation<BaseMessage[]>({
*     reducer: () => [], // ignored; DeltaChannel is supplied below
*   }),
* });
* ```
*/
var DeltaChannel = class DeltaChannel extends BaseChannel {
	lc_graph_name = "DeltaChannel";
	/** `undefined` represents the Python `MISSING` sentinel (empty channel). */
	value;
	reducer;
	snapshotFrequency;
	initialValueFactory;
	constructor(reducer, options) {
		super();
		const snapshotFrequency = options?.snapshotFrequency ?? 1e3;
		if (!Number.isInteger(snapshotFrequency) || snapshotFrequency <= 0) throw new Error(`snapshotFrequency must be a positive integer, got ${snapshotFrequency}`);
		this.reducer = reducer;
		this.snapshotFrequency = snapshotFrequency;
		this.initialValueFactory = options?.initialValueFactory ?? (() => []);
		this.value = void 0;
	}
	fromCheckpoint(checkpoint) {
		const empty = new DeltaChannel(this.reducer, {
			snapshotFrequency: this.snapshotFrequency,
			initialValueFactory: this.initialValueFactory
		});
		if (checkpoint === void 0) empty.value = this.initialValueFactory();
		else if (isDeltaSnapshot(checkpoint)) empty.value = checkpoint.value;
		else empty.value = checkpoint;
		return empty;
	}
	/**
	* Apply ancestor writes oldest-to-newest via a single reducer call.
	*
	* If any write is an Overwrite, the last one in the sequence acts as the
	* reset point: its value becomes the new base and only writes after it are
	* passed to the reducer.
	*/
	replayWrites(writes) {
		const values = writes.map((w) => w[2]);
		if (values.length === 0) return;
		let base = this.value;
		let start = 0;
		for (let i = 0; i < values.length; i += 1) {
			const [isOverwrite, overwriteValue] = _getOverwriteValue(values[i]);
			if (isOverwrite) {
				base = overwriteValue !== void 0 && overwriteValue !== null ? overwriteValue : this.initialValueFactory();
				start = i + 1;
			}
		}
		const remaining = values.slice(start);
		this.value = remaining.length > 0 ? this.reducer(base, remaining) : base;
	}
	update(values) {
		if (values.length === 0) return false;
		let overwriteValue;
		let hasOverwrite = false;
		for (const value of values) if (_isOverwriteValue(value)) {
			if (hasOverwrite) throw new InvalidUpdateError("Can receive only one Overwrite value per step.");
			hasOverwrite = true;
			[, overwriteValue] = _getOverwriteValue(value);
		}
		if (hasOverwrite) {
			this.value = overwriteValue !== void 0 && overwriteValue !== null ? overwriteValue : this.initialValueFactory();
			return true;
		}
		const base = this.value === void 0 ? this.initialValueFactory() : this.value;
		this.value = this.reducer(base, values);
		return true;
	}
	get() {
		if (this.value === void 0) throw new EmptyChannelError();
		return this.value;
	}
	/**
	* Always returns `undefined` (the Python `MISSING` sentinel). Snapshot
	* decisions live in `createCheckpoint`, which has the channel version and
	* writes a {@link DeltaSnapshot} directly into `channel_values`. For
	* non-snapshot steps the channel does not appear in `channel_values`;
	* reconstruction walks ancestor writes via the saver's
	* `getDeltaChannelHistory`.
	*/
	checkpoint() {}
	isAvailable() {
		return this.value !== void 0;
	}
	equals(other) {
		if (this === other) return true;
		if (!isDeltaChannel(other)) return false;
		if (this.snapshotFrequency !== other.snapshotFrequency) return false;
		return this.reducer === other.reducer;
	}
};
//#endregion
export { DeltaChannel };

//# sourceMappingURL=delta.js.map