const { Bookings, Users, Listings, BookingAddOns } = require('../../models');
const { formatMonthYear, errorHandler, paginate } = require('../../util');
const { buildFilter } = require('../../helpers');

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

	Bookings.findOne({
		where: {
			customer_id: customerId,
			host_id: userId,
		},
		include: [
			{
				model: Listings,
				as: 'listing',
			},
		],
		order: [['createdAt', 'DESC']],
	})
		.then((booking) => {
			Users.findOne({
				where: {
					id: customerId,
				},
			})
				.then((user) => {
					if (!user) {
						return errorHandler('Customer not found.', 404);
					}

					const mappedBooking = booking
						? {
								listingName: booking.listing.name,
								checkIn: booking.check_in,
								checkOut: booking.check_out,
								pax: booking.pax,
								totalAmount: booking.total_amount,
								status: booking.status,
							}
						: null;

					const mappedCustomer = {
						id: user.id,
						name: `${user.firstname || ''} ${user.lastname || ''}`.trim(),
						image: user.image ? `${process.env.BASE_URL}/public/user-uploads/${user.image}` : null,
						joined: formatMonthYear(user.createdAt),
						address: user.address,
						isHost: user.is_host,
					};

					return res.status(200).json({
						success: true,
						customer: mappedCustomer,
						recentBooking: mappedBooking,
					});
				})
				.catch((err) => {
					next(err);
				});
		})
		.catch((err) => {
			next(err);
		});
};

exports.getAllBookings = (req, res, next) => {
	const { userId } = req;
	const { status, page, limit, bookingDate, search, date } = req.query;

	const filter = buildFilter(userId, { status, date, bookingDate, search });

	Bookings.findAll({
		where: filter,
		attributes: ['id', 'booking_no', 'pax', 'check_in', 'check_out', 'total_amount', 'status'],
		include: [
			{
				model: Users,
				as: 'customers',
				attributes: ['firstname', 'lastname'],
			},
			{
				model: Listings,
				as: 'listing',
				attributes: ['name'],
			},
			{
				model: BookingAddOns,
				as: 'addOns',
			},
		],
		order: [['createdAt', 'DESC']],
	})
		.then((bookings) => {
			const mappedData = bookings.map((booking) => ({
				id: booking.id,
				bookingNo: booking.booking_no,
				customerName: `${booking.customers.firstname || ''} ${booking.customers.lastname || ''}`.trim(),
				listingName: booking?.listing?.name ?? 'Listing not available',
				pax: booking.pax,
				checkIn: booking.check_in,
				checkOut: booking.check_out,
				status: booking.status,
			}));

			if (!page || !limit) {
				return res.status(200).json({
					success: true,
					bookings: mappedData,
				});
			}

			const { data, pagination } = paginate(mappedData, parseInt(page), parseInt(limit));

			return res.status(200).json({
				success: true,
				pagination,
				bookings: data,
			});
		})
		.catch((err) => {
			next(err);
		});
};

exports.getBookingsByReferenceNo = (req, res, next) => {
	const { bookingNo } = req.params;

	Bookings.findOne({
		where: {
			booking_no: bookingNo,
		},
		attributes: [
			'id',
			'booking_no',
			'pax',
			'check_in',
			'check_out',
			'add_ons_total',
			'total_amount',
			'status',
			'payment_option',
			'amount_paid',
			'payment_status',
			'balance',
			'payment_method',
		],
		include: [
			{
				model: Users,
				as: 'customers',
				attributes: ['firstname', 'lastname'],
			},
			{
				model: Listings,
				as: 'listing',
				attributes: ['name'],
			},
			{
				model: BookingAddOns,
				as: 'addOns',
				attributes: ['add_on_name', 'quantity', 'price', 'total_amount'],
			},
		],
	})
		.then((booking) => {
			if (!booking) {
				return errorHandler('Booking not found.', 404);
			}

			const addOns = booking.addOns.map((addon) => ({
				name: addon.add_on_name,
				quantity: addon.quantity,
				price: addon.price,
				totalAmount: addon.total_amount,
			}));

			const mappedData = {
				id: booking.id,
				bookingNo: booking.booking_no,
				customerName: booking.customers
					? `${booking.customers.firstname || 'N/A'} ${booking.customers.lastname || 'N/A'}`
					: 'Customer not available',
				listingName: booking.listing ? booking.listing.name : 'Listing not available',
				checkIn: booking.check_in,
				checkOut: booking.check_out,
				pax: booking.pax,
				status: booking.status,
				addOnsTotal: booking.add_ons_total,
				totalAmount: booking.total_amount,
				paymentDetails: {
					amountPaid: booking.amount_paid,
					balance: booking.balance,
					option: booking.payment_option,
					status: booking.payment_status,
					method: booking.payment_method,
				},
				addOns: addOns,
			};

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

exports.deleteCancelledBooking = async (req, res, next) => {
	try {
		const { userId } = req;
		const { bookingId } = req.params;

		const booking = await Bookings.findByPk(bookingId);

		if (!booking) {
			return res.status(404).json({
				success: false,
				message: 'Booking not found',
			});
		}

		if (booking.host_id !== userId) {
			return res.status(403).json({
				success: false,
				message: 'You are not authorized to delete this booking',
			});
		}

		if (booking.status !== 'Cancelled') {
			return res.status(400).json({
				success: false,
				message: 'Only cancelled bookings can be deleted',
			});
		}

		await booking.destroy();

		await BookingAddOns.destroy({
			where: {
				booking_id: bookingId,
			},
		});

		return res.status(200).json({
			success: true,
			message: 'Booking has been deleted',
		});
	} catch (error) {
		next(error);
	}
};
