export type AgentStatusValue = "pending" | "running" | "completed" | "failed";

export interface AgentInfo {
	story_id: string;
	agent_name: string;
	status: AgentStatusValue;
	session_id: string | null;
	worktree_path: string | null;
	base_branch: string | null;
	log_session_id: string | null;
}

export interface AgentEvent {
	type:
		| "status"
		| "output"
		| "thinking"
		| "agent_json"
		| "done"
		| "error"
		| "warning";
	story_id?: string;
	agent_name?: string;
	status?: string;
	text?: string;
	data?: unknown;
	session_id?: string | null;
	message?: string;
}

export interface AgentConfigInfo {
	name: string;
	role: string;
	stage: string | null;
	model: string | null;
	allowed_tools: string[] | null;
	max_turns: number | null;
	max_budget_usd: number | null;
}

const DEFAULT_API_BASE = "/api";

function buildApiUrl(path: string, baseUrl = DEFAULT_API_BASE): string {
	return `${baseUrl}${path}`;
}

async function requestJson<T>(
	path: string,
	options: RequestInit = {},
	baseUrl = DEFAULT_API_BASE,
): Promise<T> {
	const res = await fetch(buildApiUrl(path, baseUrl), {
		headers: {
			"Content-Type": "application/json",
			...(options.headers ?? {}),
		},
		...options,
	});

	if (!res.ok) {
		const text = await res.text();
		throw new Error(text || `Request failed (${res.status})`);
	}

	return res.json() as Promise<T>;
}

export const agentsApi = {
	startAgent(storyId: string, agentName?: string, baseUrl?: string) {
		return requestJson<AgentInfo>(
			"/agents/start",
			{
				method: "POST",
				body: JSON.stringify({
					story_id: storyId,
					agent_name: agentName,
				}),
			},
			baseUrl,
		);
	},

	stopAgent(storyId: string, agentName: string, baseUrl?: string) {
		return requestJson<boolean>(
			"/agents/stop",
			{
				method: "POST",
				body: JSON.stringify({
					story_id: storyId,
					agent_name: agentName,
				}),
			},
			baseUrl,
		);
	},

	listAgents(baseUrl?: string) {
		return requestJson<AgentInfo[]>("/agents", {}, baseUrl);
	},

	getAgentConfig(baseUrl?: string) {
		return requestJson<AgentConfigInfo[]>("/agents/config", {}, baseUrl);
	},

	reloadConfig(baseUrl?: string) {
		return requestJson<AgentConfigInfo[]>(
			"/agents/config/reload",
			{ method: "POST" },
			baseUrl,
		);
	},

	getAgentOutput(storyId: string, agentName: string, baseUrl?: string) {
		return requestJson<{ output: string }>(
			`/agents/${encodeURIComponent(storyId)}/${encodeURIComponent(agentName)}/output`,
			{},
			baseUrl,
		);
	},
};

/**
 * Subscribe to SSE events for a running agent.
 * Returns a cleanup function to close the connection.
 */
export function subscribeAgentStream(
	storyId: string,
	agentName: string,
	onEvent: (event: AgentEvent) => void,
	onError?: (error: Event) => void,
): () => void {
	const url = `/agents/${encodeURIComponent(storyId)}/${encodeURIComponent(agentName)}/stream`;

	const eventSource = new EventSource(url);

	eventSource.onmessage = (e) => {
		try {
			const data = JSON.parse(e.data) as AgentEvent;
			onEvent(data);

			// Close on terminal events
			if (
				data.type === "done" ||
				data.type === "error" ||
				(data.type === "status" && data.status === "stopped")
			) {
				eventSource.close();
			}
		} catch (err) {
			console.error("Failed to parse agent event:", err);
		}
	};

	eventSource.onerror = (e) => {
		onError?.(e);
		eventSource.close();
	};

	return () => {
		eventSource.close();
	};
}
