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 {Code, CorporateInformation, DemographicInformation, Group, Type} from "@/interfaces/user";
import {addUserToGroupOnCreation} from "@/utils/registration";
import moment from "moment";
import {v4} from "uuid";
import client from "@/lib/mongodb";

const auth = getAuth(app);
const db = client.db(process.env.MONGODB_DB);

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 codeDoc = await db.collection("codes").findOne<Code>({code});

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

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

			const user = {
				...req.body,
				id: userId,
				email: email.toLowerCase(),
				desiredLevels: DEFAULT_DESIRED_LEVELS,
				levels: DEFAULT_LEVELS,
				bio: "",
				isFirstLogin: codeDoc ? codeDoc.type === "student" : true,
				profilePicture: "/defaultAvatar.png",
				focus: "academic",
				type: email.endsWith("@ecrop.dev") ? "developer" : codeDoc ? codeDoc.type : "student",
				subscriptionExpirationDate: codeDoc ? codeDoc.expiryDate : moment().subtract(1, "days").toISOString(),
				...(passport_id ? {demographicInformation: {passport_id}} : {}),
				registrationDate: new Date().toISOString(),
				status: code ? "active" : "paymentDue",
				// apparently there's an issue with the verification email system
				// therefore we will skip this requirement for now
				isVerified: true,
			};

			await db.collection("users").insertOne(user);

			if (!!codeDoc) {
				await db.collection("codes").updateOne({code: codeDoc.code}, {$set: {userId}});
				if (codeDoc.creator) await addUserToGroupOnCreation(userId, codeDoc.type, codeDoc.creator);
			}

			req.session.user = user;
			await req.session.save();

			res.status(200).json({user});
		})
		.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,
				id: userId,
				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(),
				// apparently there's an issue with the verification email system
				// therefore we will skip this requirement for now
				isVerified: true,
			};

			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 db.collection("users").insertOne(user);
			await db.collection("groups").insertMany([defaultCorporateGroup, defaultStudentsGroup, defaultTeachersGroup]);

			req.session.user = user;
			await req.session.save();

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