/// Gateway API client — used when running in gateway mode.
///
/// The gateway mode is detected by checking `GET /gateway/mode`. If it returns
/// `{ "mode": "gateway" }` the frontend switches to the gateway UI.

export interface JoinedAgent {
	id: string;
	label: string;
	address: string;
	registered_at: number;
	/// Unix timestamp of the last heartbeat from this agent.
	last_seen: number;
	/// Project this agent is assigned to, if any.
	assigned_project?: string;
}

export interface GatewayProject {
	name: string;
	url: string;
}

export interface GatewayInfo {
	active: string;
	projects: GatewayProject[];
}

export interface PipelineItem {
	story_id: string;
	name: string;
	stage: string;
	agent?: { agent_name: string; model: string; status: string } | null;
	blocked?: boolean;
	retry_count?: number;
	merge_failure?: string;
}

export interface ProjectPipelineStatus {
	active: PipelineItem[];
	backlog: { story_id: string; name: string }[];
	backlog_count: number;
	error?: string;
}

export interface AllProjectsPipeline {
	active: string;
	projects: Record<string, ProjectPipelineStatus>;
}

export interface GenerateTokenResponse {
	token: string;
}

export interface ServerMode {
	mode: "gateway" | "standard";
}

async function gatewayRequest<T>(
	path: string,
	options: RequestInit = {},
): Promise<T> {
	const res = await fetch(path, {
		headers: { "Content-Type": "application/json", ...(options.headers ?? {}) },
		...options,
	});
	if (!res.ok) {
		const text = await res.text();
		throw new Error(text || `Request failed (${res.status})`);
	}
	// DELETE /gateway/agents/:id returns 204 No Content.
	if (res.status === 204) {
		return undefined as unknown as T;
	}
	return res.json() as Promise<T>;
}

export const gatewayApi = {
	/// Returns `{ mode: "gateway" }` if this server is a gateway, otherwise rejects.
	getServerMode(): Promise<ServerMode> {
		return gatewayRequest<ServerMode>("/gateway/mode");
	},

	/// Generate a one-time join token for a new build agent.
	generateToken(): Promise<GenerateTokenResponse> {
		return gatewayRequest<GenerateTokenResponse>("/gateway/tokens", {
			method: "POST",
		});
	},

	/// List all build agents that have registered with this gateway.
	listAgents(): Promise<JoinedAgent[]> {
		return gatewayRequest<JoinedAgent[]>("/gateway/agents");
	},

	/// Remove a registered build agent by its ID.
	removeAgent(id: string): Promise<void> {
		return gatewayRequest<void>(`/gateway/agents/${id}`, {
			method: "DELETE",
		});
	},

	/// Assign an agent to a project, or unassign it by passing null.
	assignAgent(id: string, project: string | null): Promise<JoinedAgent> {
		return gatewayRequest<JoinedAgent>(`/gateway/agents/${id}/assign`, {
			method: "POST",
			body: JSON.stringify({ project }),
		});
	},

	/// Get the list of registered projects from the gateway.
	getGatewayInfo(): Promise<GatewayInfo> {
		return gatewayRequest<GatewayInfo>("/api/gateway");
	},

	/// Add a new project to the gateway config.
	addProject(name: string, url: string): Promise<GatewayProject> {
		return gatewayRequest<GatewayProject>("/api/gateway/projects", {
			method: "POST",
			body: JSON.stringify({ name, url }),
		});
	},

	/// Remove a project from the gateway config.
	removeProject(name: string): Promise<void> {
		return gatewayRequest<void>(
			`/api/gateway/projects/${encodeURIComponent(name)}`,
			{ method: "DELETE" },
		);
	},

	/// Send a heartbeat for an agent to update its last-seen timestamp.
	heartbeat(id: string): Promise<void> {
		return gatewayRequest<void>(`/gateway/agents/${id}/heartbeat`, {
			method: "POST",
		});
	},

	/// Fetch pipeline status from all registered projects.
	getAllProjectsPipeline(): Promise<AllProjectsPipeline> {
		return gatewayRequest<AllProjectsPipeline>("/api/gateway/pipeline");
	},

	/// Switch the active project.
	switchProject(project: string): Promise<{ ok: boolean; error?: string }> {
		return gatewayRequest<{ ok: boolean; error?: string }>(
			"/api/gateway/switch",
			{ method: "POST", body: JSON.stringify({ project }) },
		);
	},
};
