import {NextApiRequest, NextApiResponse} from "next";
import {createUserWithEmailAndPassword, getAuth} from "firebase/auth";
import {app} from "@/firebase";
import {sessionOptions} from "@/lib/session";
import {withIronSessionApiRoute} from "iron-session/next";
import {getFirestore, doc, setDoc, query, collection, where, getDocs} from "firebase/firestore";
import {CorporateInformation, DemographicInformation, Group, Type} from "@/interfaces/user";
import {addUserToGroupOnCreation} from "@/utils/registration";
import moment from "moment";
import {v4} from "uuid";

const auth = getAuth(app);
const db = getFirestore(app);

export default withIronSessionApiRoute(register, sessionOptions);

const DEFAULT_DESIRED_LEVELS = {
	reading: 9,
	listening: 9,
	writing: 9,
	speaking: 9,
};

const DEFAULT_LEVELS = {
	reading: 0,
	listening: 0,
	writing: 0,
	speaking: 0,
};

async function register(req: NextApiRequest, res: NextApiResponse) {
	const {type} = req.body as {
		type: "individual" | "corporate";
	};

	if (type === "individual") return registerIndividual(req, res);
	if (type === "corporate") return registerCorporate(req, res);
}

async function registerIndividual(req: NextApiRequest, res: NextApiResponse) {
	const {email, passport_id, password, code} = req.body as {
		email: string;
		passport_id?: string;
		password: string;
		code?: string;
	};

	const codeQuery = query(collection(db, "codes"), where("code", "==", code));
	const codeDocs = (await getDocs(codeQuery)).docs.filter((x) => !Object.keys(x.data()).includes("userId"));

	if (code && code.length > 0 && codeDocs.length === 0) {
		res.status(400).json({error: "Invalid Code!"});
		return;
	}

	const codeData =
		codeDocs.length > 0
			? (codeDocs[0].data() as {
					code: string;
					type: Type;
					creator?: string;
					expiryDate: Date | null;
			  })
			: undefined;

	createUserWithEmailAndPassword(auth, email.toLowerCase(), password)
		.then(async (userCredentials) => {
			const userId = userCredentials.user.uid;
			delete req.body.password;

			const user = {
				...req.body,
				email: email.toLowerCase(),
				desiredLevels: DEFAULT_DESIRED_LEVELS,
				levels: DEFAULT_LEVELS,
				bio: "",
				isFirstLogin: codeData ? codeData.type === "student" : true,
				profilePicture: "/defaultAvatar.png",
				focus: "academic",
				type: email.endsWith("@ecrop.dev") ? "developer" : codeData ? codeData.type : "student",
				subscriptionExpirationDate: codeData ? codeData.expiryDate : moment().subtract(1, "days").toISOString(),
				...(passport_id ? {demographicInformation: {passport_id}} : {}),
				registrationDate: new Date().toISOString(),
				status: code ? "active" : "paymentDue",
			};

			await setDoc(doc(db, "users", userId), user);

			if (codeDocs.length > 0 && codeData) {
				await setDoc(codeDocs[0].ref, {userId: userId}, {merge: true});
				if (codeData.creator) await addUserToGroupOnCreation(userId, codeData.type, codeData.creator);
			}

			req.session.user = {...user, id: userId};
			await req.session.save();

			res.status(200).json({user: {...user, id: userId}});
		})
		.catch((error) => {
			console.log(error);
			res.status(401).json({error});
		});
}

async function registerCorporate(req: NextApiRequest, res: NextApiResponse) {
	const {email, password} = req.body as {
		email: string;
		password: string;
		corporateInformation: CorporateInformation;
	};

	createUserWithEmailAndPassword(auth, email.toLowerCase(), password)
		.then(async (userCredentials) => {
			const userId = userCredentials.user.uid;
			delete req.body.password;

			const user = {
				...req.body,
				email: email.toLowerCase(),
				desiredLevels: DEFAULT_DESIRED_LEVELS,
				levels: DEFAULT_LEVELS,
				bio: "",
				isFirstLogin: false,
				focus: "academic",
				type: "corporate",
				subscriptionExpirationDate: req.body.subscriptionExpirationDate || null,
				status: "paymentDue",
				registrationDate: new Date().toISOString(),
			};

			const defaultTeachersGroup: Group = {
				admin: userId,
				id: v4(),
				name: "Teachers",
				participants: [],
				disableEditing: true,
			};

			const defaultStudentsGroup: Group = {
				admin: userId,
				id: v4(),
				name: "Students",
				participants: [],
				disableEditing: true,
			};

			const defaultCorporateGroup: Group = {
				admin: userId,
				id: v4(),
				name: "Corporate",
				participants: [],
				disableEditing: true,
			};

			await setDoc(doc(db, "users", userId), user);
			await setDoc(doc(db, "groups", defaultTeachersGroup.id), defaultTeachersGroup);
			await setDoc(doc(db, "groups", defaultStudentsGroup.id), defaultStudentsGroup);
			await setDoc(doc(db, "groups", defaultCorporateGroup.id), defaultCorporateGroup);

			req.session.user = {...user, id: userId};
			await req.session.save();

			res.status(200).json({user: {...user, id: userId}});
		})
		.catch((error) => {
			console.log(error);
			res.status(401).json({error});
		});
}
