// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type {NextApiRequest, NextApiResponse} from "next";
import {app, storage} from "@/firebase";
import {getFirestore, getDoc, doc, updateDoc, deleteField, setDoc} from "firebase/firestore";
import {withIronSessionApiRoute} from "iron-session/next";
import {sessionOptions} from "@/lib/session";
import {FilesStorage} from "@/interfaces/storage.files";

import {Payment} from "@/interfaces/paypal";
import fs from "fs";
import {ref, uploadBytes, deleteObject, getDownloadURL} from "firebase/storage";
import formidable from "formidable-serverless";

const db = getFirestore(app);

const getPaymentField = (type: FilesStorage) => {
	switch (type) {
		case "commission":
			return "commissionTransfer";
		case "corporate":
			return "corporateTransfer";
		default:
			return null;
	}
};

const handleDelete = async (paymentId: string, paymentField: "commissionTransfer" | "corporateTransfer") => {
	const paymentRef = doc(db, "payments", paymentId);
	const paymentDoc = await getDoc(paymentRef);
	const {[paymentField]: paymentFieldPath} = paymentDoc.data() as Payment;
	// Create a reference to the file to delete
	const documentRef = ref(storage, paymentFieldPath);
	await deleteObject(documentRef);
	await updateDoc(paymentRef, {
		[paymentField]: deleteField(),
		isPaid: false,
	});
};

const handleUpload = async (req: NextApiRequest, paymentId: string, paymentField: "commissionTransfer" | "corporateTransfer") =>
	new Promise((resolve, reject) => {
		const form = formidable({keepExtensions: true});
		form.parse(req, async (err: any, fields: any, files: any) => {
			if (err) {
				reject(err);
				return;
			}
			try {
				const {file} = files;
				const fileName = Date.now() + "-" + file.name;
				const fileRef = ref(storage, fileName);

				const binary = fs.readFileSync(file.path).buffer;
				const snapshot = await uploadBytes(fileRef, binary);
				fs.rmSync(file.path);

				const paymentRef = doc(db, "payments", paymentId);

				await updateDoc(paymentRef, {
					[paymentField]: snapshot.ref.fullPath,
				});
				resolve(snapshot.ref.fullPath);
			} catch (err) {
				reject(err);
			}
		});
	});

export default withIronSessionApiRoute(handler, sessionOptions);
async function handler(req: NextApiRequest, res: NextApiResponse) {
	if (!req.session.user) {
		res.status(401).json({ok: false});
		return;
	}

	if (req.method === "GET") return await get(req, res);
	if (req.method === "POST") return await post(req, res);
	if (req.method === "DELETE") return await del(req, res);
	if (req.method === "PATCH") return await patch(req, res);

	res.status(404).json(undefined);
}

async function get(req: NextApiRequest, res: NextApiResponse) {
	const {type, paymentId} = req.query as {
		type: FilesStorage;
		paymentId: string;
	};
	const paymentField = getPaymentField(type);

	if (paymentField === null) {
		res.status(500).json({error: "Failed to identify payment field"});
		return;
	}
	const paymentRef = doc(db, "payments", paymentId);
	const {[paymentField]: paymentFieldPath} = (await getDoc(paymentRef)).data() as Payment;

	// Create a reference to the file to delete
	const documentRef = ref(storage, paymentFieldPath);
	const url = await getDownloadURL(documentRef);
	res.status(200).json({url, name: documentRef.name});
}

async function post(req: NextApiRequest, res: NextApiResponse) {
	const {type, paymentId} = req.query as {
		type: FilesStorage;
		paymentId: string;
	};
	const paymentField = getPaymentField(type);

	if (paymentField === null) {
		res.status(500).json({error: "Failed to identify payment field"});
		return;
	}

	try {
		const ref = await handleUpload(req, paymentId, paymentField);

		const updatedDoc = (await getDoc(doc(db, "payments", paymentId))).data() as Payment;
		if (updatedDoc.commissionTransfer && updatedDoc.corporateTransfer) {
			await setDoc(doc(db, "payments", paymentId), {isPaid: true}, {merge: true});

			await setDoc(doc(db, "users", updatedDoc.corporate), {status: "active"}, {merge: true});
		}
		res.status(200).json({ref});
	} catch (error) {
		res.status(500).json({error});
	}
}

async function del(req: NextApiRequest, res: NextApiResponse) {
	const {type, paymentId} = req.query as {
		type: FilesStorage;
		paymentId: string;
	};
	const paymentField = getPaymentField(type);
	if (paymentField === null) {
		res.status(500).json({error: "Failed to identify payment field"});
		return;
	}

	try {
		await handleDelete(paymentId, paymentField);
		res.status(200).json({ok: true});
	} catch (err) {
		console.error(err);
		res.status(500).json({error: "Failed to delete file"});
	}
}

async function patch(req: NextApiRequest, res: NextApiResponse) {
	const {type, paymentId} = req.query as {
		type: FilesStorage;
		paymentId: string;
	};
	const paymentField = getPaymentField(type);
	if (paymentField === null) {
		res.status(500).json({error: "Failed to identify payment field"});
		return;
	}

	try {
		await handleDelete(paymentId, paymentField);
	} catch (err) {
		console.error(err);
		res.status(500).json({error: "Failed to delete file"});
		return;
	}

	try {
		const ref = await handleUpload(req, paymentId, paymentField);
		res.status(200).json({ref});
	} catch (err) {
		res.status(500).json({error: "Failed to upload file"});
	}
}

export const config = {
	api: {
		bodyParser: false,
	},
};
