import { describe, it, expect, beforeEach, vi } from 'vitest';
import { get } from 'svelte/store';
import {
	scheduleUndoable,
	undo,
	undoQueue,
	__flushUndoQueueForTests,
	__pendingUndoCount,
	UNDO_TTL_MS
} from './undoQueue';

beforeEach(async () => {
	vi.useRealTimers();
	await __flushUndoQueueForTests();
});

describe('undoQueue', () => {
	it('U-01: scheduling adds an entry to the queue', () => {
		scheduleUndoable({ label: 'Delete Milk', restore: () => {}, commit: () => {} });
		expect(get(undoQueue)).toHaveLength(1);
		expect(get(undoQueue)[0].label).toBe('Delete Milk');
	});

	it('U-02: undo() calls restore() and removes the entry', async () => {
		const restore = vi.fn();
		const commit = vi.fn();
		const id = scheduleUndoable({ label: 'Delete X', restore, commit });
		await undo(id);
		expect(restore).toHaveBeenCalledTimes(1);
		expect(commit).not.toHaveBeenCalled();
		expect(get(undoQueue)).toHaveLength(0);
	});

	it('U-03: after the TTL elapses, commit() fires and the entry clears', async () => {
		vi.useFakeTimers();
		const restore = vi.fn();
		const commit = vi.fn();
		scheduleUndoable({ label: 'Delete Y', restore, commit });
		expect(__pendingUndoCount()).toBe(1);

		await vi.advanceTimersByTimeAsync(UNDO_TTL_MS + 10);

		expect(restore).not.toHaveBeenCalled();
		expect(commit).toHaveBeenCalledTimes(1);
		expect(__pendingUndoCount()).toBe(0);
		expect(get(undoQueue)).toHaveLength(0);
		vi.useRealTimers();
	});

	it('U-04: calling undo() twice is a no-op on the second call', async () => {
		const restore = vi.fn();
		const id = scheduleUndoable({ label: 'X', restore, commit: () => {} });
		await undo(id);
		await undo(id);
		expect(restore).toHaveBeenCalledTimes(1);
	});

	it('U-05: custom ttlMs is honoured', async () => {
		vi.useFakeTimers();
		const commit = vi.fn();
		scheduleUndoable({ label: 'X', restore: () => {}, commit, ttlMs: 1_000 });
		await vi.advanceTimersByTimeAsync(500);
		expect(commit).not.toHaveBeenCalled();
		await vi.advanceTimersByTimeAsync(600);
		expect(commit).toHaveBeenCalledTimes(1);
		vi.useRealTimers();
	});
});
