const { Messages, Users, Sequelize, ConversationMembers } = require('../../models');
const { formatTimestamp, formatMonthYear } = require('../../util');
const {
	ensureConversationExists,
	saveMessage,
	getAllConvoByUser,
	findOrCreateConversation,
} = require('../../services');
const { Op } = require('sequelize');

exports.sendMessage = async (req, res, next) => {
	const { userId } = req;
	const { data } = req.body;
	const { convoId, content, receiverId } = data;
	const { messageAttachments } = req.files || {};

	try {
		let finalConvoId;

		if (convoId) {
			finalConvoId = await ensureConversationExists(userId, receiverId, convoId);
		} else {
			finalConvoId = await findOrCreateConversation(userId, receiverId);
		}

		await saveMessage(finalConvoId, userId, content, messageAttachments);

		res.status(200).json({
			success: true,
			message: 'Message sent successfully!',
			convoId: finalConvoId,
		});
	} catch (err) {
		next(err);
	}
};

exports.getAllMessagesByConvoId = (req, res, next) => {
	const { userId } = req;
	const { convoId } = req.params;

	ConversationMembers.findAll({
		where: { convo_id: convoId, user_id: { [Sequelize.Op.ne]: userId } },
		include: [
			{
				model: Users,
				as: 'user_members',
				attributes: ['id', 'firstname', 'lastname', 'image', 'address_city', 'address_country'],
			},
		],
	})
		.then((convoMembers) => {
			const members = convoMembers.map((member) => ({
				id: member?.user_members?.id,
				name: member?.user_members?.id
					? `${member.user_members.firstname || ''} ${member.user_members.lastname || ''}`.trim()
					: 'Unknown User',
				address: `${member?.user_members?.address_city || ''}, ${member?.user_members?.address_country || ''}`.trim(),
				joined: member?.user_members?.createdAt ? formatMonthYear(member.user_members.createdAt) : null,
			}));

			Messages.findAll({
				where: { convo_id: convoId },
				order: [['createdAt', 'DESC']],
				include: [
					{
						model: Users,
						as: 'sender',
						attributes: ['id', 'firstname', 'lastname', 'image'],
					},
				],
			})
				.then((messages) => {
					const mappedMessages = messages.map((message) => ({
						sender: message.sender
							? {
									name: `${message.sender.firstname || ''} ${message.sender.lastname || ''}`.trim(),
									image: message.sender.image
										? `${process.env.BASE_URL}/public/user-uploads/${message.sender.image}`
										: null,
								}
							: null,
						content: message.content,
						is_seen: message.is_seen,
						createdAt: formatTimestamp(message.createdAt),
					}));

					res.status(200).json({
						success: true,
						data: {
							members: members,
							messages: mappedMessages,
						},
					});
				})
				.catch((err) => {
					next(err);
				});
		})
		.catch((err) => {
			next(err);
		});
};

exports.getAllConvoByUser = async (req, res, next) => {
	try {
		const { userId } = req;
		const { status, isSeen } = req.query;

		const conversations = await getAllConvoByUser(userId, { status, isSeen });

		res.status(200).json({ success: true, conversations });
	} catch (err) {
		next(err);
	}
};

exports.seenMessages = (req, res, next) => {
	const { userId } = req;
	const { convoId } = req.params;

	Messages.update(
		{ is_seen: true },
		{
			where: {
				convo_id: convoId,
				is_seen: false,
				sender_id: { [Op.ne]: userId },
			},
		},
	)
		.then((updatedMessages) => {
			if (updatedMessages[0] === 0) {
				return res.status(200).json({ success: true });
			}

			res.status(200).json({ success: true });
		})
		.catch((err) => {
			next(err);
		});
};
