const { User, Appointment, Invitation, Withdrawal, Service, Category } = require('../models');
const { Op, fn, col, literal } = require('sequelize');
const sequelize = require('../config/database');

/**
 * Admin Statistics Service
 * Handles statistical analysis and reporting for admin dashboard
 */

/**
 * Get dashboard metrics (total users, active appointments, pending withdrawals)
 * @param {Object} options - Query options
 * @returns {Promise<Object>} Dashboard metrics
 */
const getDashboardMetrics = async (options = {}) => {
  const { startDate = '', endDate = '' } = options;

  // Build date range filter
  const dateWhere = {};
  if (startDate || endDate) {
    dateWhere.createdAt = {};
    if (startDate) {
      dateWhere.createdAt[Op.gte] = new Date(startDate);
    }
    if (endDate) {
      const endDateTime = new Date(endDate);
      endDateTime.setDate(endDateTime.getDate() + 1);
      dateWhere.createdAt[Op.lt] = endDateTime;
    }
  }

  // Get total users (all time or within date range)
  const totalUsers = await User.count({
    where: dateWhere,
  });

  // Get active appointments (pending, confirmed, in-progress)
  const activeAppointments = await Appointment.count({
    where: {
      status: {
        [Op.in]: ['pending', 'confirmed', 'in-progress'],
      },
      ...dateWhere,
    },
  });

  // Get pending withdrawals
  const pendingWithdrawals = await Withdrawal.count({
    where: {
      status: 'waiting',
      ...dateWhere,
    },
  });

  // Get total pending withdrawal amount
  const pendingWithdrawalAmount = await Withdrawal.findOne({
    where: {
      status: 'waiting',
      ...dateWhere,
    },
    attributes: [[fn('SUM', col('amount')), 'totalAmount']],
    raw: true,
  });

  return {
    totalUsers,
    activeAppointments,
    pendingWithdrawals,
    pendingWithdrawalAmount: parseFloat(pendingWithdrawalAmount?.totalAmount || 0),
  };
};

/**
 * Calculate user growth trends over time
 * @param {Object} options - Query options
 * @returns {Promise<Array>} User growth data by period
 */
const getUserGrowthTrends = async (options = {}) => {
  const { startDate = '', endDate = '', groupBy = 'day' } = options;

  // Build date range filter
  const where = {};
  if (startDate || endDate) {
    where.createdAt = {};
    if (startDate) {
      where.createdAt[Op.gte] = new Date(startDate);
    }
    if (endDate) {
      const endDateTime = new Date(endDate);
      endDateTime.setDate(endDateTime.getDate() + 1);
      where.createdAt[Op.lt] = endDateTime;
    }
  }

  // Determine date format based on groupBy
  let dateFormat;
  switch (groupBy) {
    case 'hour':
      dateFormat = '%Y-%m-%d %H:00:00';
      break;
    case 'day':
      dateFormat = '%Y-%m-%d';
      break;
    case 'week':
      dateFormat = '%Y-%u'; // Year-Week
      break;
    case 'month':
      dateFormat = '%Y-%m';
      break;
    case 'year':
      dateFormat = '%Y';
      break;
    default:
      dateFormat = '%Y-%m-%d';
  }

  // Query user growth by period
  const growthData = await User.findAll({
    where,
    attributes: [
      [fn('DATE_FORMAT', col('created_at'), dateFormat), 'period'],
      [fn('COUNT', col('id')), 'count'],
    ],
    group: [literal('period')],
    order: [[literal('period'), 'ASC']],
    raw: true,
  });

  return growthData.map((item) => ({
    period: item.period,
    count: parseInt(item.count),
  }));
};

/**
 * Calculate service popularity rankings based on appointment volume
 * @param {Object} options - Query options
 * @returns {Promise<Array>} Service rankings
 */
const getServicePopularityRankings = async (options = {}) => {
  const { startDate = '', endDate = '', limit = 10 } = options;

  // Build date range filter
  const where = {};
  if (startDate || endDate) {
    where.createdAt = {};
    if (startDate) {
      where.createdAt[Op.gte] = new Date(startDate);
    }
    if (endDate) {
      const endDateTime = new Date(endDate);
      endDateTime.setDate(endDateTime.getDate() + 1);
      where.createdAt[Op.lt] = endDateTime;
    }
  }

  // Query appointments grouped by service
  const rankings = await Appointment.findAll({
    where,
    include: [
      {
        model: Service,
        as: 'service',
        attributes: ['id', 'titleZh', 'titleEn', 'titleEs', 'image', 'price'],
        include: [
          {
            model: Category,
            as: 'category',
            attributes: ['id', 'key', 'nameZh', 'nameEn', 'nameEs'],
          },
        ],
      },
    ],
    attributes: [
      'serviceId',
      [fn('COUNT', col('Appointment.id')), 'appointmentCount'],
      [fn('SUM', col('amount')), 'totalRevenue'],
    ],
    group: [
      'serviceId',
      'service.id',
      'service.title_zh',
      'service.title_en',
      'service.title_es',
      'service.image',
      'service.price',
      'service.category.id',
      'service.category.key',
      'service.category.name_zh',
      'service.category.name_en',
      'service.category.name_es',
    ],
    order: [[literal('appointmentCount'), 'DESC']],
    limit: parseInt(limit),
    raw: true,
  });

  return rankings.map((item, index) => ({
    rank: index + 1,
    serviceId: item.serviceId,
    serviceName: {
      zh: item['service.titleZh'],
      en: item['service.titleEn'],
      es: item['service.titleEs'],
    },
    category: {
      id: item['service.category.id'],
      key: item['service.category.key'],
      name: {
        zh: item['service.category.nameZh'],
        en: item['service.category.nameEn'],
        es: item['service.category.nameEs'],
      },
    },
    appointmentCount: parseInt(item.appointmentCount),
    totalRevenue: parseFloat(item.totalRevenue || 0),
  }));
};

/**
 * Calculate invitation conversion rate
 * @param {Object} options - Query options
 * @returns {Promise<Object>} Conversion rate data
 */
const getInvitationConversionRate = async (options = {}) => {
  const { startDate = '', endDate = '' } = options;

  // Build date range filter
  const where = {};
  if (startDate || endDate) {
    where.createdAt = {};
    if (startDate) {
      where.createdAt[Op.gte] = new Date(startDate);
    }
    if (endDate) {
      const endDateTime = new Date(endDate);
      endDateTime.setDate(endDateTime.getDate() + 1);
      where.createdAt[Op.lt] = endDateTime;
    }
  }

  // Get total invitations
  const totalInvitations = await Invitation.count({
    where,
  });

  // Get invitations with first payment (converted)
  const convertedInvitations = await Invitation.count({
    where: {
      ...where,
      firstPaymentAt: {
        [Op.ne]: null,
      },
    },
  });

  // Calculate conversion rate
  const conversionRate = totalInvitations > 0 ? (convertedInvitations / totalInvitations) * 100 : 0;

  // Get total reward amount
  const rewardData = await Invitation.findOne({
    where: {
      ...where,
      rewardStatus: 'credited',
    },
    attributes: [[fn('SUM', col('reward_amount')), 'totalRewards']],
    raw: true,
  });

  const totalRewards = parseFloat(rewardData?.totalRewards || 0);

  return {
    totalInvitations,
    convertedInvitations,
    conversionRate: parseFloat(conversionRate.toFixed(2)),
    totalRewards,
  };
};

/**
 * Generate financial reports (total rewards, pending withdrawals, platform revenue)
 * @param {Object} options - Query options
 * @returns {Promise<Object>} Financial report data
 */
const getFinancialReport = async (options = {}) => {
  const { startDate = '', endDate = '' } = options;

  // Build date range filter
  const dateWhere = {};
  if (startDate || endDate) {
    dateWhere.createdAt = {};
    if (startDate) {
      dateWhere.createdAt[Op.gte] = new Date(startDate);
    }
    if (endDate) {
      const endDateTime = new Date(endDate);
      endDateTime.setDate(endDateTime.getDate() + 1);
      dateWhere.createdAt[Op.lt] = endDateTime;
    }
  }

  // Get total rewards paid (credited invitations)
  const rewardsPaidData = await Invitation.findOne({
    where: {
      ...dateWhere,
      rewardStatus: 'credited',
    },
    attributes: [[fn('SUM', col('reward_amount')), 'totalRewardsPaid']],
    raw: true,
  });

  const totalRewardsPaid = parseFloat(rewardsPaidData?.totalRewardsPaid || 0);

  // Get pending withdrawals amount
  const pendingWithdrawalsData = await Withdrawal.findOne({
    where: {
      ...dateWhere,
      status: 'waiting',
    },
    attributes: [[fn('SUM', col('amount')), 'totalPendingWithdrawals']],
    raw: true,
  });

  const totalPendingWithdrawals = parseFloat(pendingWithdrawalsData?.totalPendingWithdrawals || 0);

  // Get completed withdrawals amount
  const completedWithdrawalsData = await Withdrawal.findOne({
    where: {
      ...dateWhere,
      status: 'completed',
    },
    attributes: [[fn('SUM', col('amount')), 'totalCompletedWithdrawals']],
    raw: true,
  });

  const totalCompletedWithdrawals = parseFloat(completedWithdrawalsData?.totalCompletedWithdrawals || 0);

  // Get total appointment revenue
  const appointmentRevenueData = await Appointment.findOne({
    where: {
      ...dateWhere,
      status: 'completed',
    },
    attributes: [[fn('SUM', col('amount')), 'totalAppointmentRevenue']],
    raw: true,
  });

  const totalAppointmentRevenue = parseFloat(appointmentRevenueData?.totalAppointmentRevenue || 0);

  // Calculate platform revenue (appointment revenue - rewards paid - completed withdrawals)
  const platformRevenue = totalAppointmentRevenue - totalRewardsPaid - totalCompletedWithdrawals;

  return {
    totalRewardsPaid,
    totalPendingWithdrawals,
    totalCompletedWithdrawals,
    totalAppointmentRevenue,
    platformRevenue: parseFloat(platformRevenue.toFixed(2)),
  };
};

/**
 * Get comprehensive statistics data
 * @param {Object} options - Query options
 * @returns {Promise<Object>} Complete statistics
 */
const getStatistics = async (options = {}) => {
  const { startDate = '', endDate = '', groupBy = 'day', serviceLimit = 10 } = options;

  // Fetch all statistics in parallel
  const [dashboardMetrics, userGrowth, serviceRankings, invitationStats, financialReport] = await Promise.all([
    getDashboardMetrics({ startDate, endDate }),
    getUserGrowthTrends({ startDate, endDate, groupBy }),
    getServicePopularityRankings({ startDate, endDate, limit: serviceLimit }),
    getInvitationConversionRate({ startDate, endDate }),
    getFinancialReport({ startDate, endDate }),
  ]);

  return {
    dashboardMetrics,
    userGrowth,
    serviceRankings,
    invitationStats,
    financialReport,
  };
};

module.exports = {
  getDashboardMetrics,
  getUserGrowthTrends,
  getServicePopularityRankings,
  getInvitationConversionRate,
  getFinancialReport,
  getStatistics,
};
