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');
  }
};
