import { AxiosError } from "axios";
import { apiClient } from "./client";

export interface ToolInstance {
	id: string;
	name: string;
	display_name: string;
	tool_type_id: string;
	tool_type_name: string;
	tool_type_interfaces: string[];
	status: string;
	url: string | null;
	port: number | null;
	selected_config_profile_id: string | null;
	ssh_key_ids: string[];
	created_at: string;
}

export interface Session {
	id: string;
	display_name: string;
	tool_type_name: string;
	tool_icon: string;
	tool_type_interfaces: string[];
	repository_name: string;
	repository_id: string;
	project_name: string;
	project_id: string;
	workspace_name?: string | null;
	status: string;
	url: string | null;
	container_status?: string;
	probe_status?: string;
	created_at?: string;
}

export async function listInstances(
	projectId: string,
	repoId: string,
): Promise<ToolInstance[]> {
	const response = await apiClient.get(
		`/projects/${projectId}/repositories/${repoId}/instances`,
	);
	return response.data.instances;
}

export async function createInstance(
	projectId: string,
	repoId: string,
	toolTypeId: string,
	displayName?: string,
	workspaceId?: string,
	configProfileId?: string,
	sshKeyIds?: string[],
): Promise<ToolInstance> {
	const response = await apiClient.post(
		`/projects/${projectId}/repositories/${repoId}/instances`,
		{
			tool_type_id: toolTypeId,
			display_name: displayName,
			workspace_id: workspaceId || undefined,
			config_profile_id: configProfileId,
			ssh_key_ids: sshKeyIds || [],
		},
	);
	return response.data;
}

export async function startInstance(
	projectId: string,
	repoId: string,
	instanceId: string,
	configProfileId?: string,
	sshKeyIds?: string[],
	retries = 2,
): Promise<{ status: string; url?: string }> {
	try {
		const response = await apiClient.post(
			`/projects/${projectId}/repositories/${repoId}/instances/${instanceId}/start`,
			{ config_profile_id: configProfileId, ssh_key_ids: sshKeyIds || [] },
		);
		return response.data;
	} catch (error) {
		// Retry on network errors (e.g. Docker creating network interfaces)
		const axiosError = error as AxiosError;
		if (retries > 0 && !axiosError.response) {
			await new Promise((r) => setTimeout(r, 1500));
			return startInstance(
				projectId,
				repoId,
				instanceId,
				configProfileId,
				sshKeyIds,
				retries - 1,
			);
		}
		throw error;
	}
}

export async function stopInstance(
	projectId: string,
	repoId: string,
	instanceId: string,
): Promise<{ status: string }> {
	const response = await apiClient.post(
		`/projects/${projectId}/repositories/${repoId}/instances/${instanceId}/stop`,
	);
	return response.data;
}

export async function restartInstance(
	projectId: string,
	repoId: string,
	instanceId: string,
	configProfileId?: string,
	sshKeyIds?: string[],
	retries = 2,
): Promise<{ status: string; url?: string }> {
	try {
		const response = await apiClient.post(
			`/projects/${projectId}/repositories/${repoId}/instances/${instanceId}/restart`,
			{ config_profile_id: configProfileId, ssh_key_ids: sshKeyIds || [] },
		);
		return response.data;
	} catch (error) {
		// Retry on network errors (e.g. Docker creating network interfaces)
		const axiosError = error as AxiosError;
		if (retries > 0 && !axiosError.response) {
			await new Promise((r) => setTimeout(r, 1500));
			return restartInstance(
				projectId,
				repoId,
				instanceId,
				configProfileId,
				sshKeyIds,
				retries - 1,
			);
		}
		throw error;
	}
}

export async function deleteInstance(
	projectId: string,
	repoId: string,
	instanceId: string,
	force?: boolean,
): Promise<void> {
	await apiClient.delete(
		`/projects/${projectId}/repositories/${repoId}/instances/${instanceId}`,
		{ params: { force } },
	);
}

export async function getInstance(
	projectId: string,
	repoId: string,
	instanceId: string,
): Promise<ToolInstance> {
	const response = await apiClient.get(
		`/projects/${projectId}/repositories/${repoId}/instances/${instanceId}`,
	);
	return response.data;
}

export async function getUserSessions(): Promise<Session[]> {
	const response = await apiClient.get("/users/me/sessions");
	return response.data.sessions;
}

export interface InstanceHealth {
	healthy: boolean;
	container_status: string;
	container_health: string | null;
	container_exit_code: number | null;
	tunnel_status: string;
	tunnel_status_code: number | null;
	probe_status: string;
	last_probe_output: string | null;
	error: string | null;
}

export async function checkInstanceHealth(
	projectId: string,
	repoId: string,
	instanceId: string,
): Promise<InstanceHealth> {
	const response = await apiClient.get(
		`/projects/${projectId}/repositories/${repoId}/instances/${instanceId}/health`,
	);
	return response.data;
}

export async function renameInstance(
	projectId: string,
	repoId: string,
	instanceId: string,
	displayName: string,
): Promise<{ id: string; name: string; display_name: string }> {
	const response = await apiClient.patch(
		`/projects/${projectId}/repositories/${repoId}/instances/${instanceId}`,
		{ display_name: displayName },
	);
	return response.data;
}

export async function recreateInstanceTunnel(
	projectId: string,
	repoId: string,
	instanceId: string,
): Promise<{ status: string; url?: string }> {
	const response = await apiClient.post(
		`/projects/${projectId}/repositories/${repoId}/instances/${instanceId}/recreate-tunnel`,
	);
	return response.data;
}
