import type { Ref } from 'vue'
import type { CellPosition, Row, SpreadsheetChange } from '../types'
import { ref, computed } from 'vue'

export function useSpreadsheetUndo(
	localRows: Ref<Row[]>,
	selectionStart: Ref<CellPosition | null>,
	selectionEnd: Ref<CellPosition | null>,
	emitUpdate: () => void,
) {
	const undoStack = ref<SpreadsheetChange[]>([])
	const redoStack = ref<SpreadsheetChange[]>([])

	const canUndo = computed(() => undoStack.value.length > 0)
	const canRedo = computed(() => redoStack.value.length > 0)

	function snapshot(): SpreadsheetChange['data'] {
		return {
			rows: JSON.parse(JSON.stringify(localRows.value)),
			selection: selectionStart.value && selectionEnd.value
				? { start: { ...selectionStart.value }, end: { ...selectionEnd.value } }
				: undefined,
		}
	}

	function restoreSnapshot(change: SpreadsheetChange) {
		localRows.value = JSON.parse(JSON.stringify(change.data.rows))
		if (change.data.selection) {
			selectionStart.value = { ...change.data.selection.start }
			selectionEnd.value = { ...change.data.selection.end }
		}
		emitUpdate()
	}

	function saveState(type: SpreadsheetChange['type']) {
		undoStack.value.push({ type, data: snapshot() })
		redoStack.value = []
	}

	function undo() {
		const change = undoStack.value.pop()
		if (!change) { return }
		redoStack.value.push({ type: change.type, data: snapshot() })
		restoreSnapshot(change)
	}

	function redo() {
		const change = redoStack.value.pop()
		if (!change) { return }
		undoStack.value.push({ type: change.type, data: snapshot() })
		restoreSnapshot(change)
	}

	return { undoStack, redoStack, canUndo, canRedo, saveState, undo, redo }
}
