// 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) silently becomes a no-op.

import type { ExtensionAPI } from "@singularity-forge/pi-coding-agent";

// TODO: Replace with proper types from @singularity-forge/pi-coding-agent once
// emitExtensionEvent and the corresponding event result types are available in SF.
export type BeforeCommitEventResult = unknown;
export type BeforePrEventResult = unknown;
export type BeforePushEventResult = unknown;
export type BeforeVerifyEventResult = unknown;
export type BudgetThresholdEventResult = unknown;
export interface VerifyFailure {
	message: string;
	[key: string]: unknown;
}

let _pi: ExtensionAPI | undefined;

export function setHookEmitter(pi: ExtensionAPI): void {
	_pi = pi;
}

export function clearHookEmitter(): void {
	_pi = undefined;
}

// ─── Internal emit helper ──────────────────────────────────────────────────
// TODO: Replace with _pi.emitExtensionEvent(...) once SF's ExtensionAPI exposes it.

async function emitEvent(event: Record<string, unknown>): Promise<unknown> {
	if (!_pi) return undefined;
	// TODO: return await (_pi as any).emitExtensionEvent(event);
	void event;
	return undefined;
}

// ─── Notification ──────────────────────────────────────────────────────────

export async function emitNotification(
	kind: "blocked" | "input_needed" | "milestone_ready" | "idle" | "error",
	message: string,
	details?: Record<string, unknown>,
): Promise<void> {
	await emitEvent({ type: "notification", kind, message, details });
}

// ─── Git Lifecycle ─────────────────────────────────────────────────────────

export async function emitBeforeCommit(args: {
	message: string;
	files: string[];
	cwd: string;
	author?: string;
}): Promise<BeforeCommitEventResult | undefined> {
	return (await emitEvent({ type: "before_commit", ...args })) as BeforeCommitEventResult | undefined;
}

export async function emitCommit(args: {
	sha: string;
	message: string;
	files: string[];
	cwd: string;
}): Promise<void> {
	await emitEvent({ type: "commit", ...args });
}

export async function emitBeforePush(args: {
	remote: string;
	branch: string;
	cwd: string;
}): Promise<BeforePushEventResult | undefined> {
	return (await emitEvent({ type: "before_push", ...args })) as BeforePushEventResult | undefined;
}

export async function emitPush(args: {
	remote: string;
	branch: string;
	cwd: string;
}): Promise<void> {
	await emitEvent({ type: "push", ...args });
}

export async function emitBeforePr(args: {
	branch: string;
	targetBranch: string;
	title: string;
	body: string;
	cwd: string;
}): Promise<BeforePrEventResult | undefined> {
	return (await emitEvent({ type: "before_pr", ...args })) as BeforePrEventResult | undefined;
}

export async function emitPrOpened(args: {
	url: string;
	branch: string;
	targetBranch: string;
	cwd: string;
}): Promise<void> {
	await emitEvent({ type: "pr_opened", ...args });
}

// ─── Verification ──────────────────────────────────────────────────────────

export async function emitBeforeVerify(args: {
	unitType?: string;
	unitId?: string;
	cwd: string;
}): Promise<BeforeVerifyEventResult | undefined> {
	return (await emitEvent({ type: "before_verify", ...args })) as BeforeVerifyEventResult | undefined;
}

export async function emitVerifyResult(args: {
	passed: boolean;
	failures: VerifyFailure[];
	unitType?: string;
	unitId?: string;
	cwd: string;
}): Promise<void> {
	await emitEvent({ type: "verify_result", ...args });
}

// ─── Budget ────────────────────────────────────────────────────────────────

export async function emitBudgetThreshold(args: {
	fraction: number;
	spent: number;
	limit: number;
}): Promise<BudgetThresholdEventResult | undefined> {
	return (await emitEvent({
		type: "budget_threshold",
		fraction: args.fraction,
		spent: args.spent,
		limit: args.limit,
		currency: "USD",
	})) as BudgetThresholdEventResult | undefined;
}

// ─── Orchestrator Boundaries ───────────────────────────────────────────────

export async function emitMilestoneStart(args: {
	milestoneId: string;
	title?: string;
	cwd: string;
}): Promise<void> {
	await emitEvent({ type: "milestone_start", ...args });
}

export async function emitMilestoneEnd(args: {
	milestoneId: string;
	status: "completed" | "failed" | "cancelled";
	cwd: string;
}): Promise<void> {
	await emitEvent({ type: "milestone_end", ...args });
}

export async function emitUnitStart(args: {
	unitType: string;
	unitId: string;
	milestoneId?: string;
	cwd: string;
}): Promise<void> {
	await emitEvent({ type: "unit_start", ...args });
}

export async function emitUnitEnd(args: {
	unitType: string;
	unitId: string;
	milestoneId?: string;
	status: "completed" | "failed" | "cancelled" | "blocked";
	cwd: string;
}): Promise<void> {
	await emitEvent({ type: "unit_end", ...args });
}
