import {CorporateUser, Group, Type, User} from "@/interfaces/user";
import {getGroupsForUser, getParticipantGroups, getUserGroups, getUsersGroups} from "./groups.be";
import {last, uniq, uniqBy} from "lodash";
import {getUserCodes} from "./codes.be";
import moment from "moment";
import client from "@/lib/mongodb";

const db = client.db(process.env.MONGODB_DB);

export async function getUsers() {
	return await db.collection("users").find<User>({}).toArray();
}

export async function getUser(id: string): Promise<User | undefined> {
	const user = await db.collection("users").findOne<User>({id});
	return !!user ? user : undefined;
}

export async function getSpecificUsers(ids: string[]) {
	if (ids.length === 0) return [];

	return await db
		.collection("users")
		.find<User>({id: {$in: ids}})
		.toArray();
}

export async function getLinkedUsers(
	userID?: string,
	userType?: Type,
	type?: Type,
	page?: number,
	size?: number,
	sort?: string,
	direction?: "asc" | "desc",
) {
	const filters = {
		...(!!type ? {type} : {}),
	};

	if (!userID || userType === "admin" || userType === "developer") {
		const users = await db
			.collection("users")
			.find<User>(filters)
			.sort(sort ? {[sort]: direction === "desc" ? -1 : 1} : {})
			.skip(page && size ? page * size : 0)
			.limit(size || 0)
			.toArray();
		const total = await db.collection("users").countDocuments(filters);
		return {users, total};
	}

	const adminGroups = await getUserGroups(userID);
	const groups = await getUsersGroups(adminGroups.flatMap((x) => x.participants));
	const belongingGroups = await getParticipantGroups(userID);

	const participants = uniq([
		...adminGroups.flatMap((x) => x.participants),
		...groups.flat().flatMap((x) => x.participants),
		...(userType === "teacher" ? belongingGroups.flatMap((x) => x.participants) : []),
	]);

	//  ⨯ [FirebaseError: Invalid Query. A non-empty array is required for 'in' filters.] {
	if (participants.length === 0) return {users: [], total: 0};

	const users = await db
		.collection("users")
		.find<User>({...filters, id: {$in: participants}})
		.skip(page && size ? page * size : 0)
		.limit(size || 0)
		.toArray();
	const total = await db.collection("users").countDocuments({...filters, id: {$in: participants}});

	return {users, total};
}

export async function getUserBalance(user: User) {
	const codes = await getUserCodes(user.id);
	if (user.type !== "corporate" && user.type !== "mastercorporate") return codes.length;

	const groups = await getGroupsForUser(user.id);
	const participants = uniq(groups.flatMap((x) => x.participants));

	if (user.type === "corporate") return participants.length + codes.filter((x) => !participants.includes(x.userId || "")).length;

	const participantUsers = await Promise.all(participants.map(getUser));
	const corporateUsers = participantUsers.filter((x) => x?.type === "corporate") as CorporateUser[];

	return (
		corporateUsers.reduce((acc, curr) => acc + curr.corporateInformation?.companyInformation?.userAmount || 0, 0) +
		corporateUsers.length +
		codes.filter((x) => !participants.includes(x.userId || "") && !corporateUsers.map((u) => u.id).includes(x.userId || "")).length
	);
}
