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

vi.mock('$env/dynamic/private', () => ({
	env: { API_INTERNAL_URL: 'http://backend:8080' }
}));

vi.mock('$lib/shared/api.server', () => ({
	createApiClient: vi.fn(() => ({
		GET: vi.fn().mockResolvedValue({ response: { ok: false }, data: null })
	}))
}));

import { load } from './+page.server';

function makeEvent(search: string, canBlogWrite = true) {
	return {
		url: new URL(`http://localhost/geschichten/new${search}`),
		request: new Request(`http://localhost/geschichten/new${search}`),
		fetch: vi.fn(),
		parent: vi.fn().mockResolvedValue({ canBlogWrite })
	} as never;
}

describe('geschichten/new load — selectedType validation (security regression)', () => {
	beforeEach(() => {
		vi.clearAllMocks();
	});

	it('returns selectedType: STORY for ?type=STORY', async () => {
		const result = await load(makeEvent('?type=STORY'));
		expect(result.selectedType).toBe('STORY');
	});

	it('returns selectedType: JOURNEY for ?type=JOURNEY', async () => {
		const result = await load(makeEvent('?type=JOURNEY'));
		expect(result.selectedType).toBe('JOURNEY');
	});

	it('returns selectedType: null when ?type param is absent', async () => {
		const result = await load(makeEvent(''));
		expect(result.selectedType).toBeNull();
	});

	it('returns selectedType: null for invalid ?type param (security regression)', async () => {
		const result = await load(makeEvent('?type=ADMIN'));
		expect(result.selectedType).toBeNull();
	});

	it('returns selectedType: null for ?type=STORY%00JOURNEY (null-byte encoded — strict equality rejects it)', async () => {
		// Strict equality rejects encoded variants; .includes/.startsWith would not.
		const result = await load(makeEvent('?type=STORY%00JOURNEY'));
		expect(result.selectedType).toBeNull();
	});

	it('returns selectedType: STORY for repeated ?type=STORY&type=JOURNEY (first-value semantics — intentional)', async () => {
		// url.searchParams.get() returns the first value; this is intentional and documented.
		const result = await load(makeEvent('?type=STORY&type=JOURNEY'));
		expect(result.selectedType).toBe('STORY');
	});

	it('returns BOTH selectedType: STORY AND initialPersons when ?type=STORY&personId=p1 (no coupling)', async () => {
		const { createApiClient } = await import('$lib/shared/api.server');
		vi.mocked(createApiClient).mockReturnValue({
			GET: vi
				.fn()
				.mockResolvedValue({ response: { ok: true }, data: { id: 'p1', displayName: 'Anna' } })
		} as never);

		const result = await load(makeEvent('?type=STORY&personId=p1'));
		expect(result.selectedType).toBe('STORY');
		expect(result.initialPersons).toHaveLength(1);
	});

	it('redirects non-BLOG_WRITE users to /geschichten', async () => {
		await expect(load(makeEvent('', false))).rejects.toMatchObject({ location: '/geschichten' });
	});
});
