import { ensureMessageInstances } from "./message-coercion.js";
import { toMessageDict } from "../ui/messages.js";
//#region src/stream/optimistic-input.ts
function isBaseMessageInstance(value) {
	return value != null && typeof value.getType === "function";
}
/**
* Serialize `BaseMessage` instances under a state update's message key
* into plain message dicts so they survive JSON transport.
*
* `respond({ update })` / `respondAll({}, { update })` fold `update` into
* `Command(update=...)` on the wire. A `BaseMessage`'s default JSON form
* is the `lc` "constructor" envelope (`{ lc, type: "constructor", id,
* kwargs }`), which the server's `add_messages` reducer does **not**
* coerce — whereas the flat `{ type, content, ... }` dict that
* {@link toMessageDict} emits (and that `submit()` already sends) does.
* Mirroring the `submit()` path lets
* `respond({ update: { messages: [new AIMessage(...)] } })` behave like
* `submit({ messages: [new AIMessage(...)] })`.
*
* Only the configured `messagesKey` is touched — in both the object form
* and the `[key, value][]` tuple form. Every other key, and any already
* plain (non-`BaseMessage`) entry, passes through untouched.
*/
function serializeUpdateMessages(update, messagesKey) {
	if (Array.isArray(update)) return update.map((entry) => Array.isArray(entry) && entry[0] === messagesKey ? [entry[0], serializeMessageValue(entry[1])] : entry);
	if (!(messagesKey in update)) return update;
	return {
		...update,
		[messagesKey]: serializeMessageValue(update[messagesKey])
	};
}
function serializeMessageValue(value) {
	if (isBaseMessageInstance(value)) return toMessageDict(value);
	if (Array.isArray(value)) return value.map((item) => isBaseMessageInstance(item) ? toMessageDict(item) : item);
	return value;
}
function extractId(value) {
	const id = value?.id;
	return typeof id === "string" && id.length > 0 ? id : void 0;
}
/**
* Normalize a message-key value into an array of entries. Mirrors the
* server's `add_messages` coercion: a bare string or single message
* object is treated as a one-element list.
*/
function toEntryArray(value) {
	if (Array.isArray(value)) return value;
	return [value];
}
/**
* Build a message dict carrying `id` from an arbitrary input entry,
* without mutating the original.
*/
function toDispatchDict(entry, id) {
	if (typeof entry === "string") return {
		type: "human",
		content: entry,
		id
	};
	if (isBaseMessageInstance(entry)) return {
		...toMessageDict(entry),
		id
	};
	return {
		...entry,
		id
	};
}
/**
* Prepare a raw submit input for optimistic dispatch.
*
* @param raw         - Raw input passed to `submit()`. Must be a
*   non-null, non-array object (caller guards this).
* @param messagesKey - State key holding the message array.
* @param mintId      - Factory for stable client message ids.
* @returns The dispatch payload, optimistic messages, echoed ids, and
*   the non-message portion of the input.
*/
function prepareOptimisticInput(raw, messagesKey, mintId) {
	const dispatchInput = { ...raw };
	const extraValues = {};
	for (const key of Object.keys(raw)) if (key !== messagesKey) extraValues[key] = raw[key];
	const echoedIds = [];
	const messagesValue = raw[messagesKey];
	if (messagesValue == null) return {
		dispatchInput,
		optimisticMessages: [],
		echoedIds,
		extraValues
	};
	const entries = toEntryArray(messagesValue);
	const dispatchEntries = [];
	const optimisticDicts = [];
	for (const entry of entries) {
		if (!(typeof entry === "string" || isBaseMessageInstance(entry) || entry != null && typeof entry === "object" && !Array.isArray(entry))) {
			dispatchEntries.push(entry);
			continue;
		}
		const id = extractId(entry) ?? mintId();
		const dict = toDispatchDict(entry, id);
		dispatchEntries.push(dict);
		optimisticDicts.push(dict);
		echoedIds.push(id);
	}
	dispatchInput[messagesKey] = dispatchEntries;
	return {
		dispatchInput,
		optimisticMessages: ensureMessageInstances(optimisticDicts),
		echoedIds,
		extraValues
	};
}
//#endregion
export { prepareOptimisticInput, serializeUpdateMessages };

//# sourceMappingURL=optimistic-input.js.map