import { describe, it, expect, vi, afterEach } from 'vitest';
import { createFileLoader } from './useFileLoader.svelte';

const FAKE_URL = 'blob:fake-url';

function setupFetch(ok: boolean, body?: Blob) {
	const blob = body ?? new Blob(['fake'], { type: 'application/pdf' });
	vi.stubGlobal(
		'fetch',
		vi.fn().mockResolvedValue({
			ok,
			blob: vi.fn().mockResolvedValue(blob)
		})
	);
}

afterEach(() => {
	vi.unstubAllGlobals();
	vi.restoreAllMocks();
});

describe('createFileLoader', () => {
	it('sets fileUrl after a successful fetch', async () => {
		vi.stubGlobal('URL', {
			createObjectURL: vi.fn().mockReturnValue(FAKE_URL),
			revokeObjectURL: vi.fn()
		});
		setupFetch(true);

		const loader = createFileLoader();
		await loader.loadFile('/api/documents/1/file');

		expect(loader.fileUrl).toBe(FAKE_URL);
		expect(loader.isLoading).toBe(false);
		expect(loader.fileError).toBe('');
	});

	it('sets fileError on a failed fetch (non-ok response)', async () => {
		vi.stubGlobal('URL', {
			createObjectURL: vi.fn(),
			revokeObjectURL: vi.fn()
		});
		setupFetch(false);

		const loader = createFileLoader();
		await loader.loadFile('/api/documents/1/file');

		expect(loader.fileUrl).toBe('');
		expect(loader.fileError).not.toBe('');
		expect(loader.isLoading).toBe(false);
	});

	it('revokes the previous URL before creating a new one', async () => {
		const revokeObjectURL = vi.fn();
		vi.stubGlobal('URL', {
			createObjectURL: vi.fn().mockReturnValue(FAKE_URL),
			revokeObjectURL
		});
		setupFetch(true);

		const loader = createFileLoader();
		await loader.loadFile('/api/documents/1/file');
		// First load: no previous URL to revoke
		expect(revokeObjectURL).not.toHaveBeenCalled();

		await loader.loadFile('/api/documents/2/file');
		// Second load: previous URL should be revoked
		expect(revokeObjectURL).toHaveBeenCalledWith(FAKE_URL);
	});

	it('revokes the URL on destroy', async () => {
		const revokeObjectURL = vi.fn();
		vi.stubGlobal('URL', {
			createObjectURL: vi.fn().mockReturnValue(FAKE_URL),
			revokeObjectURL
		});
		setupFetch(true);

		const loader = createFileLoader();
		await loader.loadFile('/api/documents/1/file');
		loader.destroy();

		expect(revokeObjectURL).toHaveBeenCalledWith(FAKE_URL);
	});

	it('does not revoke when no URL has been set', () => {
		const revokeObjectURL = vi.fn();
		vi.stubGlobal('URL', {
			createObjectURL: vi.fn(),
			revokeObjectURL
		});

		const loader = createFileLoader();
		loader.destroy();

		expect(revokeObjectURL).not.toHaveBeenCalled();
	});
});
