export type GroupableDoc = {
	id: string;
	documentDate?: string | null;
	sender?: { displayName: string } | null;
	receivers?: { displayName: string }[];
};

export type DocumentGroup<T extends GroupableDoc> = {
	label: string;
	documents: T[];
};

const GROUPABLE_SORTS = ['DATE', 'SENDER', 'RECEIVER'] as const;
type GroupableSort = (typeof GROUPABLE_SORTS)[number];

export function groupDocuments<T extends GroupableDoc>(
	docs: T[],
	sort: string,
	fallbackLabel: string
): DocumentGroup<T>[] {
	if (docs.length === 0) return [];
	if (!GROUPABLE_SORTS.includes(sort as GroupableSort)) {
		return [{ label: '', documents: [...docs] }];
	}

	const groupMap = new Map<string, T[]>();
	const fallbackDocs: T[] = [];

	for (const doc of docs) {
		const keys = extractGroupKeys(doc, sort as GroupableSort);
		if (keys.length === 0) {
			fallbackDocs.push(doc);
		} else {
			for (const key of keys) {
				if (!groupMap.has(key)) groupMap.set(key, []);
				groupMap.get(key)!.push(doc);
			}
		}
	}

	const groups = [...groupMap.entries()].map(([label, documents]) => ({ label, documents }));
	if (fallbackDocs.length > 0) groups.push({ label: fallbackLabel, documents: fallbackDocs });
	return groups;
}

function extractGroupKeys<T extends GroupableDoc>(doc: T, sort: GroupableSort): string[] {
	if (sort === 'DATE') {
		const year = doc.documentDate
			? String(new Date(doc.documentDate + 'T12:00:00').getFullYear())
			: null;
		return year ? [year] : [];
	}
	if (sort === 'SENDER') return doc.sender ? [doc.sender.displayName] : [];
	if (sort === 'RECEIVER') return (doc.receivers ?? []).map((r) => r.displayName);
	return [];
}
