import { useState } from "react";
import { useMutation, useQueryClient, type QueryClient, type UseMutationOptions } from "@tanstack/react-query";

/** Which form is open: none, the create form, or the edit form for one row. */
export type CrudFormState<Entity> = { mode: "create" } | { mode: "edit"; entity: Entity };

/** The row a confirmation dialog is open for, and the message it shows. */
export interface PendingDelete<Entity> {
	entity: Entity;
	message: string;
}

type MutationFactory<Variables> = (queryClient: QueryClient) => UseMutationOptions<unknown, Error, Variables>;

export interface CrudFormSpec<Entity extends { id: number }, Input> {
	create: MutationFactory<Input>;
	update: MutationFactory<{ id: number; input: Input }>;
	remove: MutationFactory<number>;
	/** The message the confirmation dialog shows before a delete. */
	confirmDelete: (entity: Entity) => string;
}

/**
 * The create/edit/delete plumbing shared by the local DNS tabs (ruling 10):
 * three mutations, the open-form state, the pending-delete state and the
 * handlers. The field JSX, the table and the confirmation dialog stay in the
 * caller: `onDelete` opens the confirmation instead of deciding anything, so
 * the hook never reaches for `window.confirm` (ruling 5).
 */
export function useCrudForm<Entity extends { id: number }, Input>(spec: CrudFormSpec<Entity, Input>) {
	const queryClient = useQueryClient();
	const create = useMutation(spec.create(queryClient));
	const update = useMutation(spec.update(queryClient));
	const remove = useMutation(spec.remove(queryClient));
	const [form, setForm] = useState<CrudFormState<Entity> | null>(null);
	const [pendingDelete, setPendingDelete] = useState<PendingDelete<Entity> | null>(null);

	function openForm(next: CrudFormState<Entity>) {
		create.reset();
		update.reset();
		setForm(next);
	}

	function closeForm() {
		setForm(null);
	}

	function onSubmit(input: Input) {
		if (form === null) return;
		if (form.mode === "create") {
			create.mutate(input, { onSuccess: () => setForm(null) });
		} else {
			update.mutate({ id: form.entity.id, input }, { onSuccess: () => setForm(null) });
		}
	}

	function onDelete(entity: Entity) {
		setPendingDelete({ entity, message: spec.confirmDelete(entity) });
	}

	function confirmPendingDelete() {
		if (pendingDelete === null) return;
		remove.mutate(pendingDelete.entity.id);
		setPendingDelete(null);
	}

	function cancelPendingDelete() {
		setPendingDelete(null);
	}

	return {
		create,
		update,
		remove,
		form,
		openForm,
		closeForm,
		onSubmit,
		onDelete,
		pendingDelete,
		confirmPendingDelete,
		cancelPendingDelete,
	};
}
