const { Op } = require('sequelize');
const { Bookings, Sequelize, RecentlyViewedListings } = require('../models');
const { getDateRangeForFilter, setStartOfDay, setEndOfDay } = require('../helpers');
const moment = require('moment');

exports.getTotalEarnings = (userId, filter, date, month, year) => {
	let whereCondition = {
		host_id: userId,
		status: 'Done',
	};

	const today = new Date();
	const selectedDate = date ? new Date(date) : null;
	const selectedMonth = month ? parseInt(month) : today.getMonth() + 1; // default to current month if not provided
	const selectedYear = year ? parseInt(year) : today.getFullYear(); // default to current year if not provided

	if (date && isNaN(selectedDate.getTime())) {
		return Promise.reject('Invalid date format provided');
	}

	const { startOfDay, endOfDay } = getDateRangeForFilter(filter, selectedDate, selectedMonth, selectedYear, today);

	if (startOfDay && endOfDay) {
		whereCondition.updatedAt = {
			[Op.between]: [startOfDay, endOfDay],
		};
	}

	return Bookings.sum('amount_paid', {
		where: whereCondition,
	})
		.then((totalEarnings) => {
			return totalEarnings ? totalEarnings.toFixed(2) : '0.00';
		})
		.catch((err) => {
			// console.error(err);
			return '0.00';
		});
};

exports.getTotalBookings = (userId, filter, date, month, year) => {
	let whereCondition = {
		host_id: userId,
		status: 'Done',
	};

	const today = new Date();
	let selectedDate = date ? new Date(date) : null;
	let selectedMonth = month ? parseInt(month) : today.getMonth() + 1;
	let selectedYear = year ? parseInt(year) : today.getFullYear();

	if (date && isNaN(selectedDate.getTime())) {
		return Promise.reject('Invalid date format provided');
	}

	const { startOfDay, endOfDay } = getDateRangeForFilter(filter, selectedDate, selectedMonth, selectedYear, today);

	if (startOfDay && endOfDay) {
		whereCondition.updatedAt = {
			[Op.between]: [startOfDay, endOfDay],
		};
	}

	return Bookings.count({
		where: whereCondition,
	})
		.then((totalBookings) => {
			return totalBookings;
		})
		.catch((err) => {
			//   console.error(err);
			return 0;
		});
};

exports.getYearToDateSummary = (userId) => {
	const today = new Date();
	const startOfYear = new Date(today.getFullYear(), 0, 1); // January 1st
	const endOfToday = new Date(today.setHours(23, 59, 59, 999)); // end of today

	const adjustments = 0.0; // any modifications to the gross earnings, such as refunds, cancellations, or other deductions that impact the total payout
	const taxWithheld = 0.0;

	return Bookings.findAll({
		where: {
			host_id: userId,
			status: 'Done',
			updatedAt: {
				[Op.between]: [startOfYear, endOfToday],
			},
		},
		attributes: [
			[Sequelize.fn('SUM', Sequelize.col('amount_paid')), 'grossEarnings'],
			[Sequelize.fn('SUM', Sequelize.col('service_fee')), 'serviceFees'],
		],
		raw: true,
	})
		.then(([result]) => {
			const grossEarnings = parseFloat(result.grossEarnings || 0).toFixed(2);
			const serviceFees = parseFloat(result.serviceFees || 0).toFixed(2);
			const total = (grossEarnings - serviceFees - adjustments - taxWithheld).toFixed(2);

			return {
				dateRange: `Jan 1 - ${new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}`,
				grossEarnings,
				serviceFees,
				adjustments: adjustments.toFixed(2),
				taxWithheld: taxWithheld.toFixed(2),
				total,
			};
		})
		.catch((err) => {
			console.error(err);
			return {
				dateRange: `Jan 1 - ${new Date().toLocaleDateString('en-US')}`,
				grossEarnings: '0.00',
				serviceFees: '0.00',
				adjustments: '0.00',
				taxWithheld: '0.00',
				total: '0.00',
			};
		});
};

exports.getDailyTraffic = (userId) => {
	const today = new Date();

	const startOfDay = setStartOfDay(new Date(today)); // 00:00:00
	const endOfDay = setEndOfDay(new Date(today)); // 23:59:59

	let whereCondition = {
		host_id: userId,
		createdAt: {
			[Op.gte]: startOfDay,
			[Op.lt]: endOfDay,
		},
	};

	return RecentlyViewedListings.findAll({
		where: whereCondition,
		attributes: [[Sequelize.fn('COUNT', Sequelize.col('host_id')), 'trafficCount']],
		raw: true,
	})
		.then((result) => {
			const trafficCount = result.length > 0 ? result[0].trafficCount : 0;

			return {
				date: today.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }),
				trafficCount: trafficCount,
			};
		})
		.catch((error) => {
			console.error('Error fetching daily traffic data:', error.message);
			throw new Error('Unable to fetch daily traffic data');
		});
};

exports.getMonthlyTraffic = async (userId) => {
	const currentYear = moment().year();
	const months = Array.from({ length: 12 }, (_, index) => index + 1); // [1, 2, ..., 12]

	try {
		const monthlyTraffic = await Promise.all(
			months.map(async (month) => {
				const startOfMonth = moment()
					.year(currentYear)
					.month(month - 1)
					.startOf('month')
					.toDate(); // start of the month (00:00:00)

				const endOfMonth = moment()
					.year(currentYear)
					.month(month - 1)
					.endOf('month')
					.toDate(); // end of the month (23:59:59)

				const whereCondition = {
					host_id: userId,
					createdAt: {
						[Op.between]: [startOfMonth, endOfMonth],
					},
				};

				const result = await RecentlyViewedListings.findAll({
					where: whereCondition,
					attributes: [[Sequelize.fn('COUNT', Sequelize.col('host_id')), 'view_count']],
					raw: true,
				});

				const trafficCount = result.length > 0 ? result[0].view_count : 0; // default == 0

				return {
					month: moment()
						.month(month - 1)
						.format('MMMM'),
					trafficCount: trafficCount,
				};
			}),
		);

		return monthlyTraffic;
	} catch (error) {
		// console.error('Error fetching monthly traffic data:', error.message);
		throw new Error('Unable to fetch monthly traffic data');
	}
};
