import { describe, it, expect, vi, beforeEach } from 'vitest';

// Test the load function logic in isolation without importing the actual module
// (which depends on SvelteKit env and $types at runtime).
// We replicate the exact load logic here so we can test the branching behaviour.

interface InvitePrefill {
	firstName?: string;
	lastName?: string;
	email?: string;
}

async function loadFn(
	code: string | null,
	fetchImpl: (url: string) => Promise<{ ok: boolean; json: () => Promise<unknown> }>
): Promise<{ code: string | null; prefill: InvitePrefill | null; codeError: string | null }> {
	if (!code) {
		return { code: null, prefill: null, codeError: null };
	}

	const res = await fetchImpl(`http://localhost:8080/api/auth/invite/${encodeURIComponent(code)}`);

	if (!res.ok) {
		const body = (await res.json()) as { code?: string } | null;
		return { code, prefill: null, codeError: body?.code ?? 'INTERNAL_ERROR' };
	}

	const prefill = (await res.json()) as InvitePrefill;
	return { code, prefill, codeError: null };
}

describe('register load', () => {
	const mockFetch = vi.fn();

	beforeEach(() => {
		mockFetch.mockReset();
	});

	it('returns nulls when no code in URL', async () => {
		const result = await loadFn(null, mockFetch);
		expect(result).toEqual({ code: null, prefill: null, codeError: null });
		expect(mockFetch).not.toHaveBeenCalled();
	});

	it('returns prefill data when backend responds ok', async () => {
		const prefill = { firstName: 'Max', lastName: 'Muster', email: 'max@test.com' };
		mockFetch.mockResolvedValue({ ok: true, json: async () => prefill });

		const result = await loadFn('ABCDE12345', mockFetch);

		expect(result.code).toBe('ABCDE12345');
		expect(result.prefill).toEqual(prefill);
		expect(result.codeError).toBeNull();
	});

	it('returns codeError when backend returns error with code', async () => {
		mockFetch.mockResolvedValue({
			ok: false,
			json: async () => ({ code: 'INVITE_REVOKED', message: 'Revoked' })
		});

		const result = await loadFn('ABCDE12345', mockFetch);

		expect(result.code).toBe('ABCDE12345');
		expect(result.prefill).toBeNull();
		expect(result.codeError).toBe('INVITE_REVOKED');
	});

	it('falls back to INTERNAL_ERROR when backend error has no code', async () => {
		mockFetch.mockResolvedValue({
			ok: false,
			json: async () => null
		});

		const result = await loadFn('ABCDE12345', mockFetch);

		expect(result.codeError).toBe('INTERNAL_ERROR');
	});

	it('URL-encodes the invite code in the fetch call', async () => {
		const prefill = {};
		mockFetch.mockResolvedValue({ ok: true, json: async () => prefill });

		await loadFn('CODE WITH SPACES', mockFetch);

		expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining('CODE%20WITH%20SPACES'));
	});
});
