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 mockApi(users: unknown[], groups: unknown[], tags: unknown[]) {
	vi.mocked(createApiClient).mockReturnValue({
		GET: vi
			.fn()
			.mockResolvedValueOnce({ response: { ok: true }, data: users })
			.mockResolvedValueOnce({ response: { ok: true }, data: groups })
			.mockResolvedValueOnce({ response: { ok: true }, data: tags })
	} as ReturnType<typeof createApiClient>);
}

const adminUser = {
	groups: [{ permissions: ['ADMIN', 'ADMIN_USER', 'ADMIN_TAG', 'ADMIN_PERMISSION'] }]
};
const tagAdminUser = { groups: [{ permissions: ['ADMIN_TAG'] }] };
const noPermUser = { groups: [{ permissions: ['READ_ALL'] }] };

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

describe('admin layout load — permission check', () => {
	it('throws 403 when user has no admin permission', async () => {
		await expect(
			load({
				fetch: vi.fn() as unknown as typeof fetch,
				request: new Request('http://localhost/admin'),
				url: new URL('http://localhost/admin'),
				locals: { user: noPermUser }
			})
		).rejects.toMatchObject({ status: 403 });
	});

	it('throws 403 when user is undefined', async () => {
		await expect(
			load({
				fetch: vi.fn() as unknown as typeof fetch,
				request: new Request('http://localhost/admin'),
				url: new URL('http://localhost/admin'),
				locals: { user: undefined }
			})
		).rejects.toMatchObject({ status: 403 });
	});

	it('throws 403 when user has no groups', async () => {
		await expect(
			load({
				fetch: vi.fn() as unknown as typeof fetch,
				request: new Request('http://localhost/admin'),
				url: new URL('http://localhost/admin'),
				locals: { user: { groups: [] } }
			})
		).rejects.toMatchObject({ status: 403 });
	});

	it('allows access for a user with ADMIN_TAG only', async () => {
		mockApi([], [], []);
		await expect(
			load({
				fetch: vi.fn() as unknown as typeof fetch,
				request: new Request('http://localhost/admin'),
				url: new URL('http://localhost/admin'),
				locals: { user: tagAdminUser }
			})
		).resolves.toBeDefined();
	});

	it('returns entity counts and permission flags for a full admin', async () => {
		mockApi(
			[{ id: 'u1' }, { id: 'u2' }],
			[{ id: 'g1' }],
			[{ id: 't1' }, { id: 't2' }, { id: 't3' }]
		);

		const mockFetch = vi.fn().mockResolvedValue({
			ok: true,
			json: async () => [{ id: 'i1' }, { id: 'i2' }]
		});

		const result = await load({
			fetch: mockFetch as unknown as typeof fetch,
			request: new Request('http://localhost/admin'),
			url: new URL('http://localhost/admin'),
			locals: { user: adminUser }
		});

		expect(result.userCount).toBe(2);
		expect(result.groupCount).toBe(1);
		expect(result.tagCount).toBe(3);
		expect(result.inviteCount).toBe(2);
		expect(result.canManageUsers).toBe(true);
		expect(result.canManageTags).toBe(true);
		expect(result.canManagePermissions).toBe(true);
		expect(result.canRunMaintenance).toBe(true);
	});
});
