import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
import { loadEntriesFromFile } from "./load-jsonl-entries.js";
import { withTranscriptFileLock } from "./transcript-file-lock.js";
import { emitSessionTranscriptUpdate } from "../transcript-events.js";
import { buildSessionContextForLlm, isTranscriptContextEntry } from "../session-context-for-llm.js";
import { randomUUID } from "node:crypto";
import { existsSync } from "node:fs";
import path from "node:path";
import { CURRENT_SESSION_VERSION, SessionManager } from "@earendil-works/pi-coding-agent";
//#region src/session/parity/jsonl-transcript-io.ts
init_write_file_atomic();
/** Custom JSONL entry for persisted-only context rows. */
const XOPC_CONTEXT_CUSTOM_TYPE = "xopc:transcript-row";
function generateShortId(byId) {
	for (let i = 0; i < 100; i++) {
		const id = randomUUID().slice(0, 8);
		if (!byId.has(id)) return id;
	}
	return randomUUID();
}
function contextRowToCustomEntry(row, parentId, byId) {
	return {
		type: "custom",
		customType: XOPC_CONTEXT_CUSTOM_TYPE,
		id: generateShortId(byId),
		parentId,
		timestamp: row.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
		data: {
			kind: "context",
			id: row.id,
			text: row.text,
			data: row.data,
			createdAt: row.createdAt
		}
	};
}
function compactionRecordToEntry(rec, parentId, byId) {
	return {
		type: "compaction",
		id: generateShortId(byId),
		parentId,
		timestamp: rec.at,
		summary: rec.summary,
		firstKeptEntryId: String(rec.firstKeptIndex),
		tokensBefore: rec.tokensBefore,
		details: {
			tokensAfter: rec.tokensAfter,
			xopc: true
		},
		fromHook: true
	};
}
function agentMessageToEntry(msg, parentId, byId) {
	return {
		type: "message",
		id: generateShortId(byId),
		parentId,
		timestamp: (/* @__PURE__ */ new Date()).toISOString(),
		message: msg
	};
}
function transcriptRowsStrictPrefix(prev, merged) {
	if (merged.length < prev.length) return false;
	for (let i = 0; i < prev.length; i++) if (JSON.stringify(prev[i]) !== JSON.stringify(merged[i])) return false;
	return true;
}
async function writeTranscriptJsonlUnlocked(params) {
	const byId = /* @__PURE__ */ new Set();
	const lines = [];
	const header = {
		type: "session",
		version: CURRENT_SESSION_VERSION,
		id: params.sessionId,
		timestamp: (/* @__PURE__ */ new Date()).toISOString(),
		cwd: params.cwd
	};
	lines.push(JSON.stringify(header));
	let parentId = null;
	for (const row of params.rows) if (isTranscriptContextEntry(row)) {
		const e = contextRowToCustomEntry(row, parentId, byId);
		byId.add(e.id);
		lines.push(JSON.stringify(e));
		parentId = e.id;
	} else {
		const e = agentMessageToEntry(row, parentId, byId);
		byId.add(e.id);
		lines.push(JSON.stringify(e));
		parentId = e.id;
	}
	if (params.appendCompaction) {
		const e = compactionRecordToEntry(params.appendCompaction, parentId, byId);
		byId.add(e.id);
		lines.push(JSON.stringify(e));
	}
	const body = `${lines.join("\n")}\n`;
	await writeTextAtomic(params.absPath, body);
}
/**
* Map the current session branch to the same {@link TranscriptStoredRow} projection as
* {@link readTranscriptRowsFromFile} (messages + xopc context custom rows only).
*/
function branchPathToTranscriptRows(branch) {
	const rows = [];
	for (const e of branch) {
		if (e.type === "message" && "message" in e && e.message) {
			rows.push(e.message);
			continue;
		}
		if (e.type === "custom") {
			const ctx = customEntryToContextRow(e);
			if (ctx) rows.push(ctx);
		}
	}
	return rows;
}
/**
* Persist the in-memory {@link SessionManager} graph with an atomic rewrite of the JSONL file.
* Ensures durability even when pi would otherwise defer `_persist` until the first assistant message.
*/
async function writeAtomicSessionManagerSnapshot(sessionManager, absPath) {
	const header = sessionManager.getHeader();
	if (!header || header.type !== "session") throw new Error("SessionManager: missing session header for snapshot");
	const entries = sessionManager.getEntries();
	await writeTextAtomic(absPath, `${JSON.stringify(header)}\n${entries.map((e) => JSON.stringify(e)).join("\n")}\n`);
}
/**
* Serialize transcript rows to a pi-coding-agent JSONL file (linear chain).
* Always rewrites the file; guarded by a cross-process transcript lock.
*/
async function writeTranscriptJsonl(params) {
	await withTranscriptFileLock(params.absPath, async () => {
		await writeTranscriptJsonlUnlocked(params);
	});
}
/**
* Persist merged transcript rows with append optimization (strict prefix → tail append).
* Intended for hot paths that already merged prior rows with new LLM state.
*/
async function persistMergedTranscriptRows(params) {
	await withTranscriptFileLock(params.absPath, async () => {
		const prev = existsSync(params.absPath) ? await readTranscriptRowsFromFile(params.absPath) : [];
		if (params.appendCompaction || params.rows.length <= prev.length || !transcriptRowsStrictPrefix(prev, params.rows)) {
			await writeTranscriptJsonlUnlocked(params);
			return;
		}
		const sessionDir = path.dirname(params.absPath);
		const sm = SessionManager.open(params.absPath, sessionDir, params.cwd);
		const branchRows = branchPathToTranscriptRows(sm.getBranch());
		if (JSON.stringify(branchRows) !== JSON.stringify(prev)) {
			await writeTranscriptJsonlUnlocked(params);
			return;
		}
		const tail = params.rows.slice(prev.length);
		for (const row of tail) if (isTranscriptContextEntry(row)) sm.appendCustomEntry(XOPC_CONTEXT_CUSTOM_TYPE, {
			kind: "context",
			id: row.id,
			text: row.text,
			data: row.data,
			createdAt: row.createdAt
		});
		else sm.appendMessage(row);
		await writeAtomicSessionManagerSnapshot(sm, params.absPath);
	});
}
function customEntryToContextRow(entry) {
	if (entry.customType !== "xopc:transcript-row" || !entry.data || typeof entry.data !== "object") return null;
	const d = entry.data;
	if (d.kind !== "context") return null;
	return {
		kind: "context",
		id: typeof d.id === "string" ? d.id : void 0,
		text: typeof d.text === "string" ? d.text : void 0,
		data: d.data && typeof d.data === "object" && !Array.isArray(d.data) ? d.data : void 0,
		createdAt: typeof d.createdAt === "string" ? d.createdAt : entry.timestamp
	};
}
/**
* Load full transcript rows from a JSONL path (pi session file).
*/
/**
* Append one `xopc:transcript-row` context entry via pi SessionManager (OpenClaw-aligned append path).
*/
/** Append one LLM message row via pi SessionManager (slash receipts, goals, etc.). */
async function appendPiTranscriptMessage(params) {
	await withTranscriptFileLock(params.absPath, async () => {
		const sessionDir = path.dirname(params.absPath);
		const sm = SessionManager.open(params.absPath, sessionDir, params.cwd);
		sm.appendMessage(params.message);
		await writeAtomicSessionManagerSnapshot(sm, params.absPath);
		emitSessionTranscriptUpdate({
			sessionFile: params.absPath,
			sessionKey: params.sessionKey
		});
	});
}
async function appendPiTranscriptContextEntry(params) {
	await withTranscriptFileLock(params.absPath, async () => {
		const sessionDir = path.dirname(params.absPath);
		const sm = SessionManager.open(params.absPath, sessionDir, params.cwd);
		sm.appendCustomEntry(XOPC_CONTEXT_CUSTOM_TYPE, {
			kind: "context",
			id: params.entry.id,
			text: params.entry.text,
			data: params.entry.data,
			createdAt: params.entry.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
		});
		await writeAtomicSessionManagerSnapshot(sm, params.absPath);
		emitSessionTranscriptUpdate({
			sessionFile: params.absPath,
			sessionKey: params.sessionKey
		});
	});
}
async function readTranscriptRowsFromFile(absPath) {
	const entries = loadEntriesFromFile(absPath);
	const rows = [];
	for (const e of entries) {
		if (e.type === "session") continue;
		if (e.type === "message" && "message" in e && e.message) {
			rows.push(e.message);
			continue;
		}
		if (e.type === "custom") {
			const ctx = customEntryToContextRow(e);
			if (ctx) rows.push(ctx);
		}
	}
	return rows;
}
function rowsToLlmMessages(rows) {
	return buildSessionContextForLlm(rows);
}
//#endregion
export { XOPC_CONTEXT_CUSTOM_TYPE, appendPiTranscriptContextEntry, appendPiTranscriptMessage, persistMergedTranscriptRows, readTranscriptRowsFromFile, rowsToLlmMessages, writeAtomicSessionManagerSnapshot, writeTranscriptJsonl };

//# sourceMappingURL=jsonl-transcript-io.js.map