// updating specific user changes other users
// for example, updating the status of a corporate user should  update the status of all users in the same corporate group
import {UserStatus, User} from "../interfaces/user";
import {getFirestore, collection, getDocs, getDoc, doc, setDoc, query, where} from "firebase/firestore";
import {app} from "@/firebase";

const db = getFirestore(app);

export const propagateStatusChange = (userId: string, status: UserStatus) =>
	new Promise((resolve, reject) => {
		getDoc(doc(db, "users", userId))
			.then((docUser) => {
				const user = docUser.data() as User;

				// only update the status of the user's groups if the user is a corporate user
				if (user.type === "corporate" || user.type === "mastercorporate") {
					getDocs(query(collection(db, "groups"), where("admin", "==", userId))).then(async (userGroupsRef) => {
						const userGroups = userGroupsRef.docs.map((x) => x.data());

						const targetUsers = [...new Set(userGroups.flatMap((g) => g.participants).filter((u) => u))];

						Promise.all(
							targetUsers.map(async (targetUserId) => {
								const ref = await getDoc(doc(db, "users", targetUserId));

								if (!ref.exists()) return null;

								const data = ref.data() as User;
								return {...data, id: targetUserId};
							}),
						)
							.then((data) => {
								const filtered = data.filter((x) => {
									if (x === null) return false;
									if (x.status === status) return false;
									return true;
								}) as User[];

								if (filtered.length === 0) {
									return;
								}

								Promise.all(filtered.map((user: User) => setDoc(doc(db, "users", user.id), {status}, {merge: true})))
									.then(() => {
										resolve(true);
									})
									.catch((err) => {
										console.error(err);
										reject(err);
									});
							})
							.catch((err) => {
								console.error(err);
								reject(err);
							});
					});
					return;
				}

				const error = new Error("User is not a corporate user");
				console.error(error);
				reject(error);
			})
			.catch((err) => {
				console.error(err);
				reject(err);
			});
	});

export const propagateExpiryDateChanges = (userId: string, initialExpiryDate: Date | null | undefined, subscriptionExpirationDate: Date | null) =>
	new Promise((resolve, reject) => {
		getDoc(doc(db, "users", userId))
			.then((docUser) => {
				const user = docUser.data() as User;

				// only update the status of the user's groups if the user is a corporate user
				if (user.type === "corporate") {
					getDocs(query(collection(db, "groups"), where("admin", "==", userId))).then(async (userGroupsRef) => {
						const userGroups = userGroupsRef.docs.map((x) => x.data());

						const targetUsers = [...new Set(userGroups.flatMap((g) => g.participants).filter((u) => u))];

						Promise.all(
							targetUsers.map(async (targetUserId) => {
								const ref = await getDoc(doc(db, "users", targetUserId));

								if (!ref.exists()) return null;

								const data = ref.data() as User;
								return {...data, id: ref.id};
							}),
						)
							.then(async (data) => {
								const filtered = data.filter((x) => {
									if (x === null) return false;
									if (!x.subscriptionExpirationDate && !initialExpiryDate) return true;
									if (x.subscriptionExpirationDate !== initialExpiryDate) return false;
									return true;
								}) as User[];

								if (filtered.length === 0) return;

								for (const user of filtered) {
									await setDoc(doc(db, "users", user.id), {subscriptionExpirationDate}, {merge: true});
								}

								resolve(true);
							})
							.catch((err) => {
								console.error(err);
								reject(err);
							});
					});
					return;
				}

				const error = new Error("User is not a corporate user");
				console.error(error);
				reject(error);
			})
			.catch((err) => {
				console.error(err);
				reject(err);
			});
	});
