import { redirect } from '@sveltejs/kit';
import { createApiClient, extractErrorCode } from '$lib/shared/api.server';
import { getErrorMessage } from '$lib/shared/errors';
import type { components } from '$lib/generated/api';

const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;

async function resolvePersonName(
	id: string,
	api: ReturnType<typeof createApiClient>
): Promise<string> {
	if (!UUID_RE.test(id)) return '';
	try {
		const result = await api.GET('/api/persons/{id}', { params: { path: { id } } });
		if (!result.response.ok) return '';
		return result.data?.displayName ?? '';
	} catch (e) {
		console.error('[resolvePersonName] failed for id', id, e);
		return '';
	}
}

type DocumentListItem = components['schemas']['DocumentListItem'];

const VALID_SORTS = ['DATE', 'TITLE', 'SENDER', 'RECEIVER', 'UPLOAD_DATE', 'RELEVANCE'] as const;
type ValidSort = (typeof VALID_SORTS)[number];
const VALID_DIRS = ['asc', 'desc'] as const;
type ValidDir = (typeof VALID_DIRS)[number];

const PAGE_SIZE = 50;

export async function load({ url, fetch }) {
	const q = url.searchParams.get('q') || '';
	const from = url.searchParams.get('from') || '';
	const to = url.searchParams.get('to') || '';
	const senderId = url.searchParams.get('senderId') || '';
	const receiverId = url.searchParams.get('receiverId') || '';
	const tags = url.searchParams.getAll('tag');
	const rawSort = url.searchParams.get('sort') ?? 'DATE';
	const sort: ValidSort = (VALID_SORTS as readonly string[]).includes(rawSort)
		? (rawSort as ValidSort)
		: 'DATE';
	const rawDir = url.searchParams.get('dir') ?? 'desc';
	const dir: ValidDir = (VALID_DIRS as readonly string[]).includes(rawDir)
		? (rawDir as ValidDir)
		: 'desc';
	const tagQ = url.searchParams.get('tagQ') || '';
	const tagOp = url.searchParams.get('tagOp') === 'OR' ? 'OR' : 'AND';
	// Narrow the accepted truthy surface to exactly "true" (mirrors the tagOp clamp).
	const undated = url.searchParams.get('undated') === 'true';
	const page = Math.max(0, Number(url.searchParams.get('page') ?? '0') || 0);

	const api = createApiClient(fetch);

	let result;
	let initialSenderName = '';
	let initialReceiverName = '';
	try {
		[result, [initialSenderName, initialReceiverName]] = await Promise.all([
			api.GET('/api/documents/search', {
				params: {
					query: {
						q: q || undefined,
						from: from || undefined,
						to: to || undefined,
						senderId: senderId || undefined,
						receiverId: receiverId || undefined,
						tag: tags.length ? tags : undefined,
						tagQ: tagQ && !tags.length ? tagQ : undefined,
						tagOp: tagOp === 'OR' ? 'OR' : undefined,
						undated: undated || undefined,
						sort,
						dir: dir || undefined,
						page,
						size: PAGE_SIZE
					}
				}
			}),
			Promise.all([resolvePersonName(senderId, api), resolvePersonName(receiverId, api)])
		]);
	} catch {
		return {
			items: [] as DocumentListItem[],
			totalElements: 0,
			pageNumber: 0,
			pageSize: PAGE_SIZE,
			totalPages: 0,
			undatedCount: 0,
			q,
			from,
			to,
			senderId,
			receiverId,
			initialSenderName: '',
			initialReceiverName: '',
			tags,
			sort,
			dir,
			tagQ,
			tagOp,
			undated,
			error: 'Daten konnten nicht geladen werden.' as string | null
		};
	}

	if (result.response.status === 401) {
		throw redirect(302, '/login');
	}

	const errorMessage: string | null = !result.response.ok
		? (getErrorMessage(extractErrorCode(result.error)) ?? 'Daten konnten nicht geladen werden.')
		: null;

	return {
		items: (result.data?.items ?? []) as DocumentListItem[],
		totalElements: result.data?.totalElements ?? 0,
		pageNumber: result.data?.pageNumber ?? page,
		pageSize: result.data?.pageSize ?? PAGE_SIZE,
		totalPages: result.data?.totalPages ?? 0,
		// Global undated count for the active filter, across all pages (issue #668).
		undatedCount: result.data?.undatedCount ?? 0,
		q,
		from,
		to,
		senderId,
		receiverId,
		initialSenderName,
		initialReceiverName,
		tags,
		sort,
		dir,
		tagQ,
		tagOp,
		undated,
		error: errorMessage
	};
}
