const { Appointment, Service, User, Category } = require('../models');
const HotService = require('../models/HotService');
const { Op } = require('sequelize');
const logger = require('../config/logger');

/**
 * Admin Appointment Service
 * Handles appointment management operations for admin panel
 */

/**
 * Get paginated appointment list with search and filters
 * @param {Object} options - Query options
 * @returns {Promise<Object>} Appointment list with pagination
 */
const getAppointmentList = async (options = {}) => {
  const {
    page = 1,
    limit = 20,
    search = '',
    status = '',
    categoryId = '',
    serviceId = '',
    startDate = '',
    endDate = '',
    sortBy = 'createdAt',
    sortOrder = 'DESC',
  } = options;

  const offset = (page - 1) * limit;

  // Build where clause
  const where = {};

  // Filter by status
  if (status) {
    where.status = status;
  }

  // Filter by service
  if (serviceId) {
    where.serviceId = serviceId;
  }

  // Filter by date range
  if (startDate || endDate) {
    where.createdAt = {};
    if (startDate) {
      where.createdAt[Op.gte] = new Date(startDate);
    }
    if (endDate) {
      // Add one day to include the end date
      const endDateTime = new Date(endDate);
      endDateTime.setDate(endDateTime.getDate() + 1);
      where.createdAt[Op.lt] = endDateTime;
    }
  }

  // Build include clause for search and category filter
  const include = [
    {
      model: Service,
      as: 'service',
      attributes: ['id', 'titleZh', 'titleEn', 'titleEs', 'image', 'price', 'categoryId'],
      required: false,
      include: [
        {
          model: Category,
          as: 'category',
          attributes: ['id', 'key', 'nameZh', 'nameEn', 'nameEs'],
          ...(categoryId && { where: { id: categoryId } }),
        },
      ],
    },
    {
      model: HotService,
      as: 'hotService',
      attributes: ['id', 'name_zh', 'name_en', 'name_es', 'image_url', 'service_type'],
      required: false,
    },
    {
      model: User,
      as: 'user',
      attributes: ['id', 'uid', 'nickname', 'realName', 'phone', 'whatsapp', 'wechatId'],
    },
  ];

  // Search by user name, phone, appointment number
  if (search) {
    // We need to use a subquery approach for searching across relationships
    const userIds = await User.findAll({
      where: {
        [Op.or]: [
          { nickname: { [Op.like]: `%${search}%` } },
          { realName: { [Op.like]: `%${search}%` } },
          { phone: { [Op.like]: `%${search}%` } },
          { wechatId: { [Op.like]: `%${search}%` } },
        ],
      },
      attributes: ['id'],
      raw: true,
    });

    const userIdList = userIds.map((u) => u.id);

    where[Op.or] = [
      { appointmentNo: { [Op.like]: `%${search}%` } },
      { userId: { [Op.in]: userIdList } },
    ];
  }

  // Query appointments
  const { count, rows: appointments } = await Appointment.findAndCountAll({
    where,
    include,
    limit: parseInt(limit),
    offset,
    order: [[sortBy, sortOrder]],
    distinct: true, // Important for correct count with includes
  });

  return {
    appointments,
    pagination: {
      total: count,
      page: parseInt(page),
      limit: parseInt(limit),
      totalPages: Math.ceil(count / limit),
    },
  };
};

/**
 * Get detailed appointment information
 * @param {String} appointmentId - Appointment ID
 * @returns {Promise<Object>} Appointment details
 */
const getAppointmentDetails = async (appointmentId) => {
  const appointment = await Appointment.findByPk(appointmentId, {
    include: [
      {
        model: Service,
        as: 'service',
        attributes: ['id', 'titleZh', 'titleEn', 'titleEs', 'descriptionZh', 'descriptionEn', 'descriptionEs', 'image', 'price'],
        include: [
          {
            model: Category,
            as: 'category',
            attributes: ['id', 'key', 'nameZh', 'nameEn', 'nameEs'],
          },
        ],
      },
      {
        model: HotService,
        as: 'hotService',
        attributes: ['id', 'name_zh', 'name_en', 'name_es', 'image_url', 'service_type'],
      },
      {
        model: User,
        as: 'user',
        attributes: ['id', 'uid', 'nickname', 'realName', 'phone', 'whatsapp', 'wechatId', 'language', 'balance'],
      },
    ],
  });

  if (!appointment) {
    throw new Error('Appointment not found');
  }

  return appointment.toJSON();
};

/**
 * Update appointment status (admin can override any status)
 * @param {String} appointmentId - Appointment ID
 * @param {String} status - New status
 * @returns {Promise<Object>} Updated appointment
 */
const updateAppointmentStatus = async (appointmentId, status) => {
  const appointment = await Appointment.findByPk(appointmentId);

  if (!appointment) {
    throw new Error('Appointment not found');
  }

  const validStatuses = ['pending', 'confirmed', 'in-progress', 'completed', 'cancelled'];
  if (!validStatuses.includes(status)) {
    throw new Error('Invalid status value');
  }

  appointment.status = status;
  await appointment.save();

  logger.info(`Admin updated appointment ${appointmentId} status to ${status}`);

  return appointment;
};

/**
 * Generate appointment statistics report
 * @param {Object} options - Query options
 * @returns {Promise<Object>} Statistics data
 */
const getAppointmentStatistics = async (options = {}) => {
  const { startDate = '', endDate = '', categoryId = '' } = options;

  // Build where clause for date range
  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;
    }
  }

  // Build include for category filter
  const include = [];
  if (categoryId) {
    include.push({
      model: Service,
      as: 'service',
      attributes: [],
      include: [
        {
          model: Category,
          as: 'category',
          attributes: [],
          where: { id: categoryId },
        },
      ],
    });
  }

  // Get total appointments
  const totalAppointments = await Appointment.count({
    where,
    ...(include.length > 0 && { include }),
    distinct: true,
  });

  // Get appointments by status
  const appointmentsByStatus = await Appointment.findAll({
    where,
    ...(include.length > 0 && { include }),
    attributes: [
      'status',
      [require('sequelize').fn('COUNT', require('sequelize').col('Appointment.id')), 'count'],
    ],
    group: ['status'],
    raw: true,
  });

  const statusCounts = {
    pending: 0,
    confirmed: 0,
    'in-progress': 0,
    completed: 0,
    cancelled: 0,
  };

  appointmentsByStatus.forEach((stat) => {
    statusCounts[stat.status] = parseInt(stat.count);
  });

  // Calculate completion rate
  const completedCount = statusCounts.completed;
  const totalNonCancelled = totalAppointments - statusCounts.cancelled;
  const completionRate = totalNonCancelled > 0 ? (completedCount / totalNonCancelled) * 100 : 0;

  // Get total revenue (sum of amounts for completed appointments)
  const revenueResult = await Appointment.findOne({
    where: {
      ...where,
      status: 'completed',
    },
    ...(include.length > 0 && { include }),
    attributes: [[require('sequelize').fn('SUM', require('sequelize').col('Appointment.amount')), 'totalRevenue']],
    raw: true,
  });

  const totalRevenue = parseFloat(revenueResult?.totalRevenue || 0);

  // Get appointments by service (top 10)
  const appointmentsByService = await Appointment.findAll({
    where,
    include: [
      {
        model: Service,
        as: 'service',
        attributes: ['id', 'titleZh', 'titleEn', 'titleEs'],
        ...(categoryId && {
          include: [
            {
              model: Category,
              as: 'category',
              attributes: [],
              where: { id: categoryId },
            },
          ],
        }),
      },
    ],
    attributes: [
      'serviceId',
      [require('sequelize').fn('COUNT', require('sequelize').col('Appointment.id')), 'count'],
    ],
    group: ['serviceId', 'service.id', 'service.titleZh', 'service.titleEn', 'service.titleEs'],
    order: [[require('sequelize').literal('count'), 'DESC']],
    limit: 10,
    raw: true,
  });

  return {
    totalAppointments,
    statusCounts,
    completionRate: parseFloat(completionRate.toFixed(2)),
    totalRevenue,
    topServices: appointmentsByService.map((item) => ({
      serviceId: item.serviceId,
      serviceName: {
        zh: item['service.titleZh'],
        en: item['service.titleEn'],
        es: item['service.titleEs'],
      },
      count: parseInt(item.count),
    })),
  };
};

module.exports = {
  getAppointmentList,
  getAppointmentDetails,
  updateAppointmentStatus,
  getAppointmentStatistics,
};
