// yoinked from https://github.com/backstage/backstage/blob/96b23786f648ea28c2ab81d4888c46ab8bbd907b/plugins/org/src/helpers/helpers.ts

import {
	CompoundEntityRef,
	DEFAULT_NAMESPACE,
	GroupEntity,
	RELATION_PARENT_OF,
	stringifyEntityRef,
	UserEntity,
} from '@backstage/catalog-model';
import {
	CatalogApi,
	getEntityRelations,
} from '@backstage/plugin-catalog-react';

export const getDescendantGroupsFromGroup = async (
	group: GroupEntity,
	catalogApi: CatalogApi
) => {
	const alreadyQueuedOrExpandedGroupNames = new Map<string, boolean>();
	const groupRef: CompoundEntityRef = {
		kind: group.kind,
		namespace: group.metadata.namespace ?? DEFAULT_NAMESPACE,
		name: group.metadata.name,
	};

	const groupQueue = [groupRef];
	const resultantGroupRefs: CompoundEntityRef[] = [];

	// Continue expanding groups until there are no more
	while (groupQueue.length > 0) {
		const activeGroupRef = groupQueue.shift() as CompoundEntityRef;
		const activeGroup = await catalogApi.getEntityByRef(activeGroupRef);
		alreadyQueuedOrExpandedGroupNames.set(
			stringifyEntityRef(activeGroupRef),
			true
		);

		const childGroups = getEntityRelations(activeGroup, RELATION_PARENT_OF, {
			kind: 'Group',
		}).filter(
			(currentGroup) =>
				!alreadyQueuedOrExpandedGroupNames.has(stringifyEntityRef(currentGroup))
		);
		childGroups.forEach((childGroup) =>
			alreadyQueuedOrExpandedGroupNames.set(
				stringifyEntityRef(childGroup),
				true
			)
		);

		groupQueue.push(...childGroups);
		resultantGroupRefs.push(...childGroups);
	}

	return resultantGroupRefs;
};

export const getMembersFromGroups = async (
	groups: CompoundEntityRef[],
	catalogApi: CatalogApi
) => {
	const membersList =
		groups.length === 0
			? { items: [] }
			: await catalogApi.getEntities({
					filter: {
						kind: 'User',
						'relations.memberof': groups.map((group) =>
							stringifyEntityRef({
								kind: 'group',
								namespace: group.namespace.toLocaleLowerCase('en-US'),
								name: group.name.toLocaleLowerCase('en-US'),
							})
						),
					},
			  });

	return membersList.items as UserEntity[];
};

export const getAllDesendantMembersForGroupEntity = async (
	groupEntity: GroupEntity,
	catalogApi: CatalogApi
) =>
	getMembersFromGroups(
		await getDescendantGroupsFromGroup(groupEntity, catalogApi),
		catalogApi
	);
