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

vi.mock('$lib/shared/api.server', () => ({
	createApiClient: vi.fn(),
	extractErrorCode: (e: unknown) => (e as { code?: string } | undefined)?.code
}));

import { load } from './+page.server';
import { createApiClient } from '$lib/shared/api.server';
import { getErrorMessage } from '$lib/shared/errors';

beforeEach(() => vi.clearAllMocks());

const TIMELINE = { years: [{ year: 1914, entries: [] }], undated: [] };

function mockApi(opts: { ok?: boolean; status?: number; data?: unknown; error?: unknown }) {
	const { ok = true, status = 200, data = TIMELINE, error } = opts;
	const GET = vi.fn().mockResolvedValue({
		response: { ok, status },
		data: ok ? data : undefined,
		error
	});
	vi.mocked(createApiClient).mockReturnValue({ GET } as unknown as ReturnType<
		typeof createApiClient
	>);
	return GET;
}

function callLoad() {
	return load({
		fetch: vi.fn() as unknown as typeof fetch,
		url: new URL('http://localhost/zeitstrahl'),
		request: new Request('http://localhost/zeitstrahl'),
		route: { id: '/zeitstrahl' },
		params: {}
	} as unknown as Parameters<typeof load>[0]);
}

describe('zeitstrahl +page.server load', () => {
	it('fetches GET /api/timeline and returns { timeline } on ok (REQ-001/002)', async () => {
		const GET = mockApi({ data: TIMELINE });
		const result = await callLoad();
		expect(GET).toHaveBeenCalledWith('/api/timeline');
		expect(result).toEqual({ timeline: TIMELINE });
	});

	it('redirects to /login on 401 (REQ-022)', async () => {
		mockApi({ ok: false, status: 401 });
		await expect(callLoad()).rejects.toMatchObject({ status: 302, location: '/login' });
	});

	it('throws a mapped error on 404 (REQ-022)', async () => {
		mockApi({ ok: false, status: 404, error: { code: 'TIMELINE_EVENT_NOT_FOUND' } });
		await expect(callLoad()).rejects.toMatchObject({
			status: 404,
			body: { message: getErrorMessage('TIMELINE_EVENT_NOT_FOUND') }
		});
	});

	it('throws a mapped error on 500 (REQ-022)', async () => {
		mockApi({ ok: false, status: 500, error: undefined });
		await expect(callLoad()).rejects.toMatchObject({ status: 500 });
	});

	it('throws a mapped FORBIDDEN error on 403 (REQ-022)', async () => {
		mockApi({ ok: false, status: 403, error: { code: 'FORBIDDEN' } });
		await expect(callLoad()).rejects.toMatchObject({
			status: 403,
			body: { message: getErrorMessage('FORBIDDEN') }
		});
	});
});
