// SF Session Todo Tool — per-session task checklist that survives context compaction.
//
// Purpose: give the agent a durable, file-backed checklist of in-session tasks
// that is not lost when the context window compacts. Items are persisted to
// .sf/session_todo.json and injected into the pre-compaction snapshot so the
// agent can reconstruct its checklist after resuming.
//
// Consumer: autonomous agent units and interactive sessions that need to track
// multiple sub-tasks within a single turn sequence without relying on context
// window memory alone.
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";

const TODO_FILENAME = "session_todo.json";

function todoPath(baseDir) {
	return join(baseDir, ".sf", TODO_FILENAME);
}

function loadTodos(baseDir) {
	const path = todoPath(baseDir);
	if (!existsSync(path)) return [];
	try {
		const parsed = JSON.parse(readFileSync(path, "utf-8"));
		return Array.isArray(parsed) ? parsed : [];
	} catch {
		return [];
	}
}

function saveTodos(baseDir, todos) {
	const sfDir = join(baseDir, ".sf");
	if (!existsSync(sfDir)) mkdirSync(sfDir, { recursive: true });
	writeFileSync(todoPath(baseDir), JSON.stringify(todos, null, 2), "utf-8");
}

function nextId(_todos) {
	// Short base-36 timestamp suffix for readable IDs.
	return `t${Date.now().toString(36)}`;
}

/**
 * Add a new todo item. Returns the new item's id.
 *
 * Purpose: append a task to the session checklist so it survives compaction.
 * Consumer: agent planning phase and interactive sessions.
 */
export function executeSessionTodoAdd(params, baseDir) {
	const todos = loadTodos(baseDir);
	const id = nextId(todos);
	const item = {
		id,
		text: params.text,
		done: false,
		created_at: new Date().toISOString(),
	};
	todos.push(item);
	saveTodos(baseDir, todos);
	return {
		content: [{ type: "text", text: `Added [${id}]: ${params.text}` }],
		details: { operation: "add", item },
	};
}

/**
 * Mark a todo item as done by id.
 *
 * Purpose: check off a completed sub-task so the checklist reflects progress.
 * Consumer: agent completing sub-tasks within a unit.
 */
export function executeSessionTodoCheck(params, baseDir) {
	const todos = loadTodos(baseDir);
	const item = todos.find((t) => t.id === params.id);
	if (!item) {
		return {
			content: [{ type: "text", text: `Todo [${params.id}] not found.` }],
			details: { operation: "check", error: "not_found" },
			isError: true,
		};
	}
	item.done = true;
	item.done_at = new Date().toISOString();
	saveTodos(baseDir, todos);
	return {
		content: [
			{ type: "text", text: `Checked off [${params.id}]: ${item.text}` },
		],
		details: { operation: "check", item },
	};
}

/**
 * List all session todo items.
 *
 * Purpose: show the current checklist state so the agent knows what remains.
 * Consumer: agent at start of each turn or after compaction via resume_agent.
 */
export function executeSessionTodoList(baseDir) {
	const todos = loadTodos(baseDir);
	if (todos.length === 0) {
		return {
			content: [{ type: "text", text: "No session todos." }],
			details: { operation: "list", todos: [] },
		};
	}
	const lines = todos.map((t) => `[${t.done ? "x" : " "}] ${t.id}: ${t.text}`);
	return {
		content: [{ type: "text", text: lines.join("\n") }],
		details: { operation: "list", todos },
	};
}

/**
 * Return a compact plaintext summary of pending todos for compaction injection.
 *
 * Purpose: ensure the session checklist is not lost during context compaction —
 * this summary is included in the compaction block so the agent can reconstruct
 * its task list after resuming.
 * Consumer: session_before_compact hook in register-hooks.js.
 */
export function getSessionTodoCompactionBlock(baseDir) {
	const todos = loadTodos(baseDir);
	const pending = todos.filter((t) => !t.done);
	if (pending.length === 0) return null;
	const lines = pending.map((t) => `  [ ] ${t.id}: ${t.text}`);
	return `Session todos (pending):\n${lines.join("\n")}`;
}
