import { describe, it, expect } from 'vitest';
import Graph from 'graphology';
import { buildDragPositions, computeDragUpdates, isDragPrevented } from '../hooks/useDragStateMachine';

describe('useDragStateMachine', () => {
	describe('buildDragPositions', () => {
		it('returns empty map for empty selection', () => {
			const graph = new Graph();
			const result = buildDragPositions(graph, new Set());
			expect(result.size).toBe(0);
		});

		it('collects positions of selected nodes', () => {
			const graph = new Graph();
			graph.addNode('n1', { x: 10, y: 20 });
			graph.addNode('n2', { x: 30, y: 40 });
			const result = buildDragPositions(graph, new Set(['n1', 'n2']));
			expect(result.size).toBe(2);
			expect(result.get('n1')).toEqual({ x: 10, y: 20 });
			expect(result.get('n2')).toEqual({ x: 30, y: 40 });
		});

		it('skips non-existent nodes', () => {
			const graph = new Graph();
			graph.addNode('n1', { x: 10, y: 20 });
			const result = buildDragPositions(graph, new Set(['n1', 'missing']));
			expect(result.size).toBe(1);
		});
	});

	describe('computeDragUpdates', () => {
		it('applies delta scaled by zoom', () => {
			const graph = new Graph();
			graph.addNode('n1', { x: 10, y: 20 });
			const initial = new Map([['n1', { x: 10, y: 20 }]]);

			const updates = computeDragUpdates(initial, 100, 200, 2, graph);
			expect(updates).toHaveLength(1);
			expect(updates[0].id).toBe('n1');
			expect(updates[0].pos.x).toBe(60);  // 10 + 100/2
			expect(updates[0].pos.y).toBe(120); // 20 + 200/2
		});

		it('returns empty when node removed during drag', () => {
			const graph = new Graph();
			const initial = new Map([['removed', { x: 0, y: 0 }]]);
			const updates = computeDragUpdates(initial, 10, 10, 1, graph);
			expect(updates).toHaveLength(0);
		});

		it('handles zoom=1 as identity', () => {
			const graph = new Graph();
			graph.addNode('n1', { x: 0, y: 0 });
			const initial = new Map([['n1', { x: 0, y: 0 }]]);
			const updates = computeDragUpdates(initial, 50, 75, 1, graph);
			expect(updates[0].pos).toEqual({ x: 50, y: 75 });
		});
	});

	describe('isDragPrevented', () => {
		it('returns true for INPUT elements', () => {
			const el = document.createElement('input');
			expect(isDragPrevented(el)).toBe(true);
		});

		it('returns true for TEXTAREA elements', () => {
			const el = document.createElement('textarea');
			expect(isDragPrevented(el)).toBe(true);
		});

		it('returns true for SELECT elements', () => {
			const el = document.createElement('select');
			expect(isDragPrevented(el)).toBe(true);
		});

		it('returns true for elements with data-no-drag', () => {
			const parent = document.createElement('div');
			parent.setAttribute('data-no-drag', 'true');
			const child = document.createElement('span');
			parent.appendChild(child);
			expect(isDragPrevented(child)).toBe(true);
		});

		it('returns false for regular div', () => {
			const el = document.createElement('div');
			expect(isDragPrevented(el)).toBe(false);
		});
	});
});
