// SF Extension — Layer 2 Event Emitter Bridge
//
// Holds a module-scoped reference to the ExtensionAPI so deeply-nested code
// (auto-loop, git-service callers, verification, budget) can emit Layer 2
// events without having to thread `pi` through every function signature.
//
// Set once from `registerSfExtension`. All emitters are best-effort — a
// missing `pi` (e.g. in standalone unit tests) logs a warning so callers know
// hooks won't fire, but never throws.

import { getErrorMessage } from "./error-utils.js";
import { logWarning } from "./workflow-logger.js";

let _pi;
let _missingPiWarningLogged = false;
export function setHookEmitter(pi) {
	_pi = pi;
	_missingPiWarningLogged = false;
}
export function clearHookEmitter() {
	_pi = undefined;
}
// ─── Internal emit helper ──────────────────────────────────────────────────
async function emitEvent(event) {
	if (!_pi) {
		// Log warning once per session when hooks fire but _pi is missing
		// (#sf-moobmhx4-gk9g83)
		if (!_missingPiWarningLogged) {
			_missingPiWarningLogged = true;
			logWarning(
				"hook",
				"ExtensionAPI not set — hooks will not fire. Call setHookEmitter(pi) from registerSfExtension to enable.",
			);
		}
		return undefined;
	}
	// Call emitExtensionEvent if available on the ExtensionAPI
	const emitter = _pi.emitExtensionEvent;
	if (typeof emitter === "function") {
		try {
			return await emitter.call(_pi, event);
		} catch (err) {
			logWarning(
				"hook",
				`emitExtensionEvent failed for ${event.type}: ${getErrorMessage(err)}`,
			);
			return undefined;
		}
	}
	// emitExtensionEvent not available on this ExtensionAPI version
	return undefined;
}
// ─── Notification ──────────────────────────────────────────────────────────
export async function emitNotification(kind, message, details) {
	await emitEvent({ type: "notification", kind, message, details });
}
// ─── Git Lifecycle ─────────────────────────────────────────────────────────
export async function emitBeforeCommit(args) {
	return await emitEvent({
		type: "before_commit",
		...args,
	});
}
export async function emitCommit(args) {
	await emitEvent({ type: "commit", ...args });
}
export async function emitBeforePush(args) {
	return await emitEvent({
		type: "before_push",
		...args,
	});
}
export async function emitPush(args) {
	await emitEvent({ type: "push", ...args });
}
export async function emitBeforePr(args) {
	return await emitEvent({
		type: "before_pr",
		...args,
	});
}
export async function emitPrOpened(args) {
	await emitEvent({ type: "pr_opened", ...args });
}
// ─── Verification ──────────────────────────────────────────────────────────
export async function emitBeforeVerify(args) {
	return await emitEvent({
		type: "before_verify",
		...args,
	});
}
export async function emitVerifyResult(args) {
	await emitEvent({ type: "verify_result", ...args });
}
// ─── Budget ────────────────────────────────────────────────────────────────
export async function emitBudgetThreshold(args) {
	return await emitEvent({
		type: "budget_threshold",
		fraction: args.fraction,
		spent: args.spent,
		limit: args.limit,
		currency: "USD",
	});
}
// ─── Orchestrator Boundaries ───────────────────────────────────────────────
export async function emitMilestoneStart(args) {
	await emitEvent({ type: "milestone_start", ...args });
}
export async function emitMilestoneEnd(args) {
	await emitEvent({ type: "milestone_end", ...args });
}
export async function emitUnitStart(args) {
	await emitEvent({ type: "unit_start", ...args });
}
export async function emitUnitEnd(args) {
	await emitEvent({ type: "unit_end", ...args });
}
