import { useState, useCallback } from "react";
import {
	stopInstance,
	deleteInstance,
	startInstance,
	recreateInstanceTunnel,
} from "../api/sessions";
import type { Session } from "../api/sessions";

interface UseInstanceActionsOptions {
	onRefresh: () => Promise<void>;
}

interface UseInstanceActionsReturn {
	loadingSessionId: string | null;
	dirtyDeleteSession: Session | null;
	dirtyDeleteFiles: string[];
	handleOpen: (session: Session) => void;
	handleStart: (session: Session) => Promise<void>;
	handleStop: (session: Session) => Promise<void>;
	handleDelete: (session: Session) => Promise<void>;
	handleForceDelete: (session: Session) => Promise<void>;
	handleRecreateTunnel: (session: Session) => Promise<void>;
	clearDirtyDelete: () => void;
}

export function useInstanceActions(
	options: UseInstanceActionsOptions,
): UseInstanceActionsReturn {
	const { onRefresh } = options;
	const [loadingSessionId, setLoadingSessionId] = useState<string | null>(null);
	const [dirtyDeleteSession, setDirtyDeleteSession] = useState<Session | null>(
		null,
	);
	const [dirtyDeleteFiles, setDirtyDeleteFiles] = useState<string[]>([]);

	const handleOpen = useCallback((session: Session) => {
		if (session.url) {
			window.open(session.url, "_blank", "noopener,noreferrer");
			return;
		}
		if (session.tool_type_interfaces?.includes("terminal")) {
			window.location.href = `/instances/${session.id}/terminal`;
			return;
		}
		window.location.href = `/projects/${session.project_id}`;
	}, []);

	const handleStart = useCallback(
		async (session: Session) => {
			if (loadingSessionId === session.id) return;
			setLoadingSessionId(session.id);
			try {
				await startInstance(
					session.project_id,
					session.repository_id,
					session.id,
				);
				await onRefresh();
			} catch {
				// ignore
			} finally {
				setLoadingSessionId(null);
			}
		},
		[loadingSessionId, onRefresh],
	);

	const handleStop = useCallback(
		async (session: Session) => {
			if (loadingSessionId === session.id) return;
			setLoadingSessionId(session.id);
			try {
				await stopInstance(
					session.project_id,
					session.repository_id,
					session.id,
				);
				await onRefresh();
			} catch {
				// ignore
			} finally {
				setLoadingSessionId(null);
			}
		},
		[loadingSessionId, onRefresh],
	);

	const handleDelete = useCallback(
		async (session: Session) => {
			if (loadingSessionId === session.id) return;
			setLoadingSessionId(session.id);
			try {
				await deleteInstance(
					session.project_id,
					session.repository_id,
					session.id,
				);
				setDirtyDeleteSession(null);
				setDirtyDeleteFiles([]);
				await onRefresh();
			} catch (error) {
				const axiosError = error as {
					response?: {
						status?: number;
						data?: { detail?: { changed_files?: string[] } };
					};
				};
				if (axiosError.response?.status === 409) {
					const detail = axiosError.response.data?.detail;
					if (detail?.changed_files) {
						setDirtyDeleteSession(session);
						setDirtyDeleteFiles(detail.changed_files);
						return;
					}
				}
			} finally {
				setLoadingSessionId(null);
			}
		},
		[loadingSessionId, onRefresh],
	);

	const handleForceDelete = useCallback(
		async (session: Session) => {
			if (loadingSessionId === session.id) return;
			setLoadingSessionId(session.id);
			try {
				await deleteInstance(
					session.project_id,
					session.repository_id,
					session.id,
					true,
				);
				setDirtyDeleteSession(null);
				setDirtyDeleteFiles([]);
				await onRefresh();
			} catch {
				// ignore
			} finally {
				setLoadingSessionId(null);
			}
		},
		[loadingSessionId, onRefresh],
	);

	const handleRecreateTunnel = useCallback(
		async (session: Session) => {
			if (loadingSessionId === session.id) return;
			setLoadingSessionId(session.id);
			try {
				await recreateInstanceTunnel(
					session.project_id,
					session.repository_id,
					session.id,
				);
				await onRefresh();
			} catch (err) {
				const message =
					(err as { response?: { data?: { detail?: string } } })?.response?.data
						?.detail || "Failed to recreate tunnel";
				alert(message);
			} finally {
				setLoadingSessionId(null);
			}
		},
		[loadingSessionId, onRefresh],
	);

	const clearDirtyDelete = useCallback(() => {
		setDirtyDeleteSession(null);
		setDirtyDeleteFiles([]);
	}, []);

	return {
		loadingSessionId,
		dirtyDeleteSession,
		dirtyDeleteFiles,
		handleOpen,
		handleStart,
		handleStop,
		handleDelete,
		handleForceDelete,
		handleRecreateTunnel,
		clearDirtyDelete,
	};
}
