/**
 * Test the front+back transcript truncation in memory-extractor.
 *
 * Previously: front-preserving truncation dropped the tail, where
 * the highest-signal content for memory extraction lives (final
 * summary, what got committed, verification outcome).
 *
 * Now: keep ~25% from front + ~75% from back with a marker in
 * between. This test pins the invariants:
 *   - identity for short inputs
 *   - both ends survive when text exceeds cap
 *   - the marker is present so the LLM knows about the elision
 *   - output length never exceeds maxChars
 */

import assert from "node:assert/strict";
import { test } from "vitest";
import { truncateMiddle } from "../memory-extractor.js";

test("identity when text fits", () => {
	assert.equal(truncateMiddle("hello world", 30_000), "hello world");
	assert.equal(truncateMiddle("", 30_000), "");
});

test("keeps front and back, drops middle, inserts marker", () => {
	// Pick sizes so the surviving front + back ≪ middle, so the
	// middle is meaningfully dropped (not just partly nibbled).
	const front = "FRONT".repeat(1000); // 5K
	const middle = "MIDDLE".repeat(20_000); // 120K
	const back = "BACK".repeat(1000); // 4K
	const text = front + middle + back; // 129K
	const out = truncateMiddle(text, 10_000);
	assert.ok(out.length <= 10_000, `output too long: ${out.length}`);
	assert.match(out, /\[…truncated middle…\]/, "marker missing");
	// Original front survives (first slice of FRONT pattern).
	assert.ok(out.startsWith("FRONT"), "front not preserved");
	// Original back survives (last slice ends with BACK pattern).
	assert.ok(out.endsWith("BACK"), "back not preserved");
	// Most of the giant middle is dropped — output is dramatically
	// smaller than the input (>10× compression).
	assert.ok(out.length < text.length / 10, `expected heavy compression`);
});

test("back-weighted split (75% back vs 25% front by default)", () => {
	// Construct a text where each char identifies its position bucket.
	const text = "F".repeat(10_000) + "M".repeat(10_000) + "B".repeat(10_000); // 30K
	const out = truncateMiddle(text, 10_000);
	const [head, tail] = out.split("[…truncated middle…]");
	// Front share ≈ 25% of (10_000 - marker_len) ≈ ~2.5K. Back ≈ 7.5K.
	assert.ok(
		head.length < tail.length,
		`expected back to be larger than front: front=${head.length} back=${tail.length}`,
	);
	assert.ok(
		tail.length > head.length * 2,
		`expected back to be > 2× front: front=${head.length} back=${tail.length}`,
	);
});

test("respects custom frontShare", () => {
	const text = "X".repeat(20_000);
	const out = truncateMiddle(text, 5_000, 0.5);
	const [head, tail] = out.split("[…truncated middle…]");
	// 50/50 split.
	assert.ok(
		Math.abs(head.length - tail.length) <= 1,
		`50/50 split should be balanced: front=${head.length} back=${tail.length}`,
	);
});

test("output length never exceeds maxChars even with marker", () => {
	for (const cap of [100, 500, 1_000, 30_000]) {
		const text = "Z".repeat(cap * 3);
		const out = truncateMiddle(text, cap);
		assert.ok(
			out.length <= cap,
			`cap=${cap}: output length ${out.length} exceeded cap`,
		);
	}
});
