import { describe, expect, it, vi, beforeEach } from 'vitest';
import { load } from './+layout.server';

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

import { createApiClient } from '$lib/shared/api.server';

function mockTreeApi(tree: unknown[]) {
	vi.mocked(createApiClient).mockReturnValue({
		GET: vi.fn().mockResolvedValueOnce({ response: { ok: true }, data: tree })
	} as ReturnType<typeof createApiClient>);
}

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

const sampleTree = [
	{
		id: 'parent1',
		name: 'Familie',
		color: 'teal',
		documentCount: 3,
		parentId: null,
		children: [
			{
				id: 'child1',
				name: 'Eltern',
				color: null,
				documentCount: 2,
				parentId: 'parent1',
				children: []
			}
		]
	},
	{
		id: 'root2',
		name: 'Urlaub',
		color: null,
		documentCount: 1,
		parentId: null,
		children: []
	}
];

describe('admin/tags layout load', () => {
	it('returns the tree list', async () => {
		mockTreeApi(sampleTree);
		const result = await load({
			fetch: vi.fn() as unknown as typeof fetch,
			request: new Request('http://localhost/admin/tags'),
			url: new URL('http://localhost/admin/tags')
		});
		expect(result.tree).toHaveLength(2);
		expect(result.tree[0].name).toBe('Familie');
	});

	it('returns an empty tree when the API returns nothing', async () => {
		mockTreeApi([]);
		const result = await load({
			fetch: vi.fn() as unknown as typeof fetch,
			request: new Request('http://localhost/admin/tags'),
			url: new URL('http://localhost/admin/tags')
		});
		expect(result.tree).toEqual([]);
	});

	it('calls GET /api/tags/tree', async () => {
		const mockGet = vi.fn().mockResolvedValue({ response: { ok: true }, data: [] });
		vi.mocked(createApiClient).mockReturnValue({ GET: mockGet } as ReturnType<
			typeof createApiClient
		>);
		await load({
			fetch: vi.fn() as unknown as typeof fetch,
			request: new Request('http://localhost/admin/tags'),
			url: new URL('http://localhost/admin/tags')
		});
		expect(mockGet).toHaveBeenCalledWith('/api/tags/tree');
	});

	it('flattens the tree into a flat tags array', async () => {
		mockTreeApi(sampleTree);
		const result = await load({
			fetch: vi.fn() as unknown as typeof fetch,
			request: new Request('http://localhost/admin/tags'),
			url: new URL('http://localhost/admin/tags')
		});
		// Both parent and child should be in the flat array
		expect(result.tags).toHaveLength(3);
		expect(result.tags.map((t) => t.name)).toContain('Eltern');
	});

	it('preserves parentId on child tags in the flat array', async () => {
		mockTreeApi(sampleTree);
		const result = await load({
			fetch: vi.fn() as unknown as typeof fetch,
			request: new Request('http://localhost/admin/tags'),
			url: new URL('http://localhost/admin/tags')
		});
		const child = result.tags.find((t) => t.name === 'Eltern');
		expect(child?.parentId).toBe('parent1');
	});

	it('sets parentId to undefined on root tags in the flat array', async () => {
		mockTreeApi(sampleTree);
		const result = await load({
			fetch: vi.fn() as unknown as typeof fetch,
			request: new Request('http://localhost/admin/tags'),
			url: new URL('http://localhost/admin/tags')
		});
		const root = result.tags.find((t) => t.name === 'Familie');
		expect(root?.parentId).toBeUndefined();
	});
});
