const { Activities, ActivityBookings, Members, sequelize } = require('../../models');
const { errorHandler } = require('../../util');
const { formatCase } = require('../../util/formatter');
const { generateReferenceNumber } = require('../../util/reference-no');

exports.bookActivity = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const { activityId: activity_id, dateTime: date_time, participants } = req.body;
		const { memberId } = req;

		if (!activity_id || !date_time || !participants) {
			return errorHandler('Activity ID, date time, and participants are required', 400);
		}

		const activity = await Activities.findByPk(activity_id);
		if (!activity) {
			return errorHandler('Activity not found', 404);
		}

		if (participants < 1) {
			return errorHandler('Number of participants must be at least 1', 400);
		}

		const activityPrice = parseFloat(activity.price);
		const priceType = activity.price_type || 'per person';

		let totalAmount;
		if (priceType === 'per person') {
			totalAmount = activityPrice * parseInt(participants);
		} else {
			totalAmount = activityPrice;
		}

		let booking = await ActivityBookings.create(
			{
				activity_id,
				member_id: memberId,
				date_time,
				participants: parseInt(participants),
				price: activityPrice,
				price_type: priceType,
				total: totalAmount,
				status: 'Unpaid',
				reference_no: await generateReferenceNumber(ActivityBookings),
			},
			{ transaction },
		);

		await transaction.commit();
		transaction = null;

		return res.status(201).json({
			success: true,
			message: 'Activity booking created successfully',
			data: formatCase(booking.get({ plain: true })),
		});
	} catch (error) {
		if (transaction) await transaction.rollback();
		next(error);
	}
};

exports.getAllActivityBookings = async (req, res, next) => {
	try {
		const { memberId } = req;
		const { page = 1, limit = 10, status, payment_status } = req.query;

		const offset = (parseInt(page) - 1) * parseInt(limit);

		let whereClause = { member_id: memberId };
		if (status) {
			whereClause.booking_status = status;
		}
		if (payment_status) {
			whereClause.payment_status = payment_status;
		}

		const { count, rows } = await ActivityBookings.findAndCountAll({
			where: whereClause,
			include: [
				{
					model: Activities,
					as: 'activity',
					attributes: ['id', 'title', 'price', 'location', 'duration'],
				},
			],
			order: [['createdAt', 'DESC']],
			limit: parseInt(limit),
			offset: offset,
		});

		const bookings = [];

		for (const item of rows) {
			let booking = item.get({ plain: true });

			if (booking.status === 'Pending') {
				const now = new Date();
				const bookingDate = new Date(booking.date_time);
				if (bookingDate < now) {
					booking.status = 'Completed';
					await item.update({ status: 'Completed' });
				}
			}

			bookings.push(booking);
		}

		return res.status(200).json({
			success: true,
			data: {
				bookings: formatCase(bookings),
				pagination: {
					currentPage: parseInt(page),
					totalPages: Math.ceil(count / parseInt(limit)),
					totalItems: count,
					itemsPerPage: parseInt(limit),
				},
			},
		});
	} catch (error) {
		next(error);
	}
};

exports.getActivityBooking = async (req, res, next) => {
	try {
		const { id } = req.params;
		const { memberId } = req;

		const booking = await ActivityBookings.findOne({
			where: { id, member_id: memberId },
			include: [
				{
					model: Activities,
					as: 'activity',
					attributes: ['id', 'title', 'price', 'location', 'duration', 'description'],
				},
				{
					model: Members,
					as: 'member',
					attributes: ['id', 'first_name', 'last_name', 'email', 'phone'],
				},
			],
		});

		if (!booking) {
			return errorHandler('Booking not found', 404);
		}

		return res.status(200).json({
			success: true,
			data: formatCase(booking.get({ plain: true })),
		});
	} catch (error) {
		next(error);
	}
};

// exports.updateActivityBooking = async (req, res, next) => {
// 	const transaction = await sequelize.transaction();
// 	try {
// 		const { id } = req.params;
// 		const { participants, booking_date, payment, special_requests } = req.body;
// 		const { memberId } = req;

// 		const booking = await ActivityBookings.findOne({
// 			where: { id, member_id: memberId },
// 		});

// 		if (!booking) {
// 			return errorHandler('Booking not found', 404);
// 		}

// 		// Check if booking can be updated (only pending bookings)
// 		if (booking.booking_status === 'Completed') {
// 			return errorHandler('Cannot update completed bookings. Please contact support.', 400);
// 		}

// 		if (booking.booking_status === 'Cancelled') {
// 			return errorHandler('Cannot update cancelled bookings', 400);
// 		}

// 		// Get activity for price calculation
// 		const activity = await Activities.findByPk(booking.activity_id);

// 		// Recalculate if participants changed
// 		let updateData = {};
// 		if (participants && participants !== booking.participants) {
// 			const activityPrice = parseFloat(activity.price);
// 			const priceType = activity.price_type || 'per person';

// 			let newTotal;
// 			if (priceType === 'per person') {
// 				newTotal = activityPrice * parseInt(participants);
// 			} else {
// 				// fixed pricing
// 				newTotal = activityPrice;
// 			}

// 			const currentPayment = parseFloat(payment) || booking.payment;
// 			const newBalance = newTotal - currentPayment;

// 			let paymentStatus = 'Pending Payment';
// 			if (currentPayment >= newTotal) {
// 				paymentStatus = 'Paid';
// 			} else if (currentPayment > 0) {
// 				paymentStatus = 'Partially Paid';
// 			}

// 			updateData = {
// 				participants: parseInt(participants),
// 				price: activityPrice,
// 				price_type: priceType,
// 				total: newTotal,
// 				balance: newBalance,
// 				payment_status: paymentStatus,
// 				...updateData,
// 			};
// 		}

// 		// Update other fields
// 		if (booking_date) updateData.booking_date = booking_date;
// 		if (payment !== undefined) {
// 			const paymentAmount = parseFloat(payment);
// 			const newBalance = booking.total - paymentAmount;

// 			let paymentStatus = 'Pending Payment';
// 			if (paymentAmount >= booking.total) {
// 				paymentStatus = 'Paid';
// 			} else if (paymentAmount > 0) {
// 				paymentStatus = 'Partially Paid';
// 			}

// 			updateData.payment = paymentAmount;
// 			updateData.balance = newBalance;
// 			updateData.payment_status = paymentStatus;
// 		}
// 		if (special_requests !== undefined) updateData.special_requests = special_requests;

// 		await booking.update(updateData, { transaction });

// 		await transaction.commit();

// 		// Get updated booking with relations
// 		const updatedBooking = await ActivityBookings.findByPk(id, {
// 			include: [
// 				{
// 					model: Activities,
// 					as: 'activity',
// 					attributes: ['id', 'title', 'price', 'location'],
// 				},
// 			],
// 		});

// 		return res.status(200).json({
// 			success: true,
// 			message: 'Booking updated successfully',
// 			data: formatCase(updatedBooking.get({ plain: true })),
// 		});
// 	} catch (error) {
// 		if (transaction) await transaction.rollback();
// 		next(error);
// 	}
// };

// exports.cancelActivityBooking = async (req, res, next) => {
// 	const transaction = await sequelize.transaction();
// 	try {
// 		const { id } = req.params;
// 		const { memberId } = req;

// 		const booking = await ActivityBookings.findOne({
// 			where: { id, member_id: memberId },
// 		});

// 		if (!booking) {
// 			return errorHandler('Booking not found', 404);
// 		}

// 		if (booking.booking_status === 'Cancelled') {
// 			return errorHandler('Booking is already cancelled', 400);
// 		}

// 		// Update booking status
// 		await booking.update({ booking_status: 'Cancelled' }, { transaction });

// 		await transaction.commit();

// 		return res.status(200).json({
// 			success: true,
// 			message: 'Booking cancelled successfully',
// 			data: formatCase(booking.get({ plain: true })),
// 		});
// 	} catch (error) {
// 		if (transaction) await transaction.rollback();
// 		next(error);
// 	}
// };

exports.makePayment = async (req, res, next) => {
	const transaction = await sequelize.transaction();
	try {
		const { paymentMethod: payment_method, bookingId } = req.body;
		const payment = Number(req.body.payment) || 0;
		if (!payment || !payment_method) {
			return errorHandler('Payment amount and payment method are required', 400);
		}

		const booking = await ActivityBookings.findByPk(bookingId);

		if (!booking) {
			return errorHandler('Booking not found', 404);
		}

		if (booking.status === 'Successful') {
			return errorHandler('Payment already made for this booking', 400);
		}

		if (booking.payment_status === 'Paid') {
			return errorHandler('Payment already made for this booking', 400);
		}

		const paymentAmount = payment;
		const newTotalPayment = Number(booking.payment) + paymentAmount;

		let paymentStatus = 'Pending Payment';
		if (newTotalPayment >= Number(booking.total)) {
			paymentStatus = 'Paid';
		} else if (newTotalPayment > 0) {
			paymentStatus = 'Partially Paid';
		}

		await booking.update(
			{
				payment: newTotalPayment,
				payment_status: paymentStatus,
				payment_method: payment_method,
				status: paymentStatus === 'Paid' ? 'Successful' : booking.status,
			},
			{ transaction },
		);

		await transaction.commit();

		return res.status(200).json({
			success: true,
			message: 'Payment processed successfully',
			data: formatCase(booking.get({ plain: true })),
		});
	} catch (error) {
		if (transaction) await transaction.rollback();
		next(error);
	}
};
