/**
 * SF Lifecycle Hooks (Tier 1.2 Phase 3b)
 *
 * Purpose: integrate SM sync and other cleanup operations into unit/session lifecycle.
 * Ensures durable operations (memory sync) complete before unit transitions to terminal state.
 *
 * Consumer: unit-runtime.js, dispatch-engine.js, or unit completion handlers.
 */

import { getErrorMessage } from "./error-utils.js";
import { flushSyncQueue } from "./sync-scheduler.js";

/**
 * Flush SM sync queue for a project before unit completes.
 * Called at session-end or unit terminal transition.
 *
 * @param {string} projectId - Project identifier (typically process.cwd())
 * @returns {Promise<object>} - { synced, failed, elapsed }
 */
export async function flushProjectMemorySync(projectId) {
	const start = Date.now();

	try {
		const result = await flushSyncQueue(projectId);
		const elapsed = Date.now() - start;

		return {
			...result,
			elapsed,
			status: "ok",
		};
	} catch (err) {
		const elapsed = Date.now() - start;

		return {
			synced: 0,
			failed: 0,
			elapsed,
			status: "error",
			reason: getErrorMessage(err),
		};
	}
}

/**
 * Flush all projects' SM queues (for session-end cleanup).
 * Use with caution; only call when all unit activity is done.
 *
 * @param {string[]} projectIds - Array of project identifiers
 * @returns {Promise<object>} - { totalSynced, totalFailed, results }
 */
export async function flushAllProjectsMemorySync(projectIds) {
	const results = [];
	let totalSynced = 0;
	let totalFailed = 0;

	for (const projectId of projectIds) {
		const result = await flushProjectMemorySync(projectId);
		results.push({ projectId, ...result });
		totalSynced += result.synced;
		totalFailed += result.failed;
	}

	return {
		totalSynced,
		totalFailed,
		results,
	};
}

/**
 * Handle unit completion: flush queued memories before marking unit complete.
 * Called from unit-runtime or dispatch-engine before transitioning to terminal state.
 *
 * @param {string} unitId - Unit identifier
 * @param {string} projectId - Project identifier
 * @param {string} finalStatus - Terminal status (completed, failed, cancelled, etc.)
 * @returns {Promise<object>} - { status, syncResult }
 */
export async function onUnitTerminal(unitId, projectId, finalStatus) {
	// Flush memory queue for this project
	const syncResult = await flushProjectMemorySync(projectId);

	// Log for debugging if needed
	if (syncResult.status === "error") {
		if (process.env.DEBUG_LIFECYCLE_FLUSH) {
			console.warn(
				`[lifecycle] unit ${unitId} terminal flush failed: ${syncResult.reason}`,
			);
		}
	} else if (syncResult.failed > 0) {
		if (process.env.DEBUG_LIFECYCLE_FLUSH) {
			console.warn(
				`[lifecycle] unit ${unitId} had ${syncResult.failed} failed syncs`,
			);
		}
	}

	// Unit should complete regardless of sync result (best-effort)
	return {
		unitId,
		finalStatus,
		syncResult,
	};
}

/**
 * Handle session end: flush all projects' memory queues.
 * Called from dispatcher or bootstrap cleanup.
 *
 * @param {string[]} projectIds - Project identifiers (or use [process.cwd()])
 * @returns {Promise<object>} - { status, flushedProjects, totalSynced, totalFailed }
 */
export async function onSessionEnd(projectIds = [process.cwd()]) {
	const result = await flushAllProjectsMemorySync(projectIds);

	if (process.env.DEBUG_LIFECYCLE_FLUSH) {
		console.log(
			`[lifecycle] session end: flushed ${result.totalSynced} memories, ${result.totalFailed} failed`,
		);
	}

	return {
		status: "ok",
		flushedProjects: projectIds.length,
		...result,
	};
}
