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

/**
 * Appointment business logic
 */
class AppointmentService {
  /**
   * Valid status transitions
   */
  static STATUS_TRANSITIONS = {
    pending: ['confirmed', 'cancelled'],
    confirmed: ['in-progress', 'cancelled'],
    'in-progress': ['completed', 'cancelled'],
    completed: [],
    cancelled: [],
  };

  /**
   * Generate unique appointment number
   * Format: APT + YYYYMMDD + 6-digit random number
   * @returns {string} - Unique appointment number
   */
  static async generateAppointmentNo() {
    const date = new Date();
    const dateStr = date.toISOString().slice(0, 10).replace(/-/g, '');
    
    let appointmentNo;
    let attempts = 0;
    const maxAttempts = 10;

    while (attempts < maxAttempts) {
      const randomNum = Math.floor(100000 + Math.random() * 900000);
      appointmentNo = `APT${dateStr}${randomNum}`;

      // Check if this number already exists
      const existing = await Appointment.findOne({
        where: { appointmentNo },
      });

      if (!existing) {
        return appointmentNo;
      }

      attempts++;
    }

    // Fallback: use timestamp
    appointmentNo = `APT${dateStr}${Date.now().toString().slice(-6)}`;
    return appointmentNo;
  }

  /**
   * Validate status transition
   * @param {string} currentStatus - Current appointment status
   * @param {string} newStatus - New status to transition to
   * @returns {boolean} - Whether transition is valid
   */
  static isValidStatusTransition(currentStatus, newStatus) {
    const allowedTransitions = this.STATUS_TRANSITIONS[currentStatus] || [];
    return allowedTransitions.includes(newStatus);
  }

  /**
   * Create a new appointment
   * @param {Object} appointmentData - Appointment data
   * @param {string} userId - User ID
   * @returns {Promise<Object>} - Created appointment
   */
  static async createAppointment(appointmentData, userId) {
    try {
      let service = null;
      let hotService = null;
      
      // 验证服务来源（serviceId 或 hotServiceId 至少有一个）
      if (appointmentData.serviceId) {
        service = await Service.findByPk(appointmentData.serviceId);
        if (!service) {
          throw new Error('SERVICE_NOT_FOUND');
        }
      } else if (appointmentData.hotServiceId) {
        // 从热门服务创建预约
        const HotService = require('../models/HotService');
        hotService = await HotService.findByPk(appointmentData.hotServiceId);
        if (!hotService) {
          throw new Error('HOT_SERVICE_NOT_FOUND');
        }
      }

      // Generate appointment number
      const appointmentNo = await this.generateAppointmentNo();

      // Create appointment with all fields
      const appointment = await Appointment.create({
        userId,
        serviceId: appointmentData.serviceId || null,
        hotServiceId: appointmentData.hotServiceId || null,
        serviceType: appointmentData.serviceType || (hotService ? hotService.service_type : null),
        appointmentNo,
        realName: appointmentData.realName,
        // 兼容旧的联系方式字段
        contactMethod: appointmentData.contactMethod,
        contactValue: appointmentData.contactValue,
        // 新的多联系方式字段
        wechatId: appointmentData.wechatId,
        phone: appointmentData.phone,
        phoneCountryCode: appointmentData.phoneCountryCode,
        whatsapp: appointmentData.whatsapp,
        // 通用预约字段
        appointmentDate: appointmentData.appointmentDate,
        appointmentTime: appointmentData.appointmentTime,
        notes: appointmentData.notes,
        amount: appointmentData.amount || (service ? service.price : null),
        status: 'pending',
        // 机票预约专用字段
        tripType: appointmentData.tripType,
        departureDate: appointmentData.departureDate,
        returnDate: appointmentData.returnDate,
        departureCity: appointmentData.departureCity,
        arrivalCity: appointmentData.arrivalCity,
        adultCount: appointmentData.adultCount,
        childCount: appointmentData.childCount,
        infantCount: appointmentData.infantCount,
        cabinType: appointmentData.cabinType,
        luggageCount: appointmentData.luggageCount,
        // 酒店预定专用字段
        checkInDate: appointmentData.checkInDate,
        checkOutDate: appointmentData.checkOutDate,
        countryCity: appointmentData.countryCity,
        hotelName: appointmentData.hotelName,
        roomCount: appointmentData.roomCount,
        roomType: appointmentData.roomType,
        needMeal: appointmentData.needMeal,
        mealPlan: appointmentData.mealPlan,
        // VIP贵宾室/接送机专用字段
        arrivalFlightNo: appointmentData.arrivalFlightNo,
        departureFlightNo: appointmentData.departureFlightNo,
        airportTerminal: appointmentData.airportTerminal,
        deliveryAddress: appointmentData.deliveryAddress,
        // 无成人陪伴儿童专用字段
        itinerary: appointmentData.itinerary,
        childAge: appointmentData.childAge,
        boyCount: appointmentData.boyCount,
        girlCount: appointmentData.girlCount,
        // 高铁票代订专用字段
        originStation: appointmentData.originStation,
        destinationStation: appointmentData.destinationStation,
        seatClass: appointmentData.seatClass,
        passengerCount: appointmentData.passengerCount,
        // 医疗/特殊需求专用字段
        hospitalName: appointmentData.hospitalName,
        conditionDescription: appointmentData.conditionDescription,
        specialAssistanceReason: appointmentData.specialAssistanceReason,
        // 宠物托运专用字段
        origin: appointmentData.origin,
        destination: appointmentData.destination,
        flightNo: appointmentData.flightNo,
        petType: appointmentData.petType,
        petName: appointmentData.petName,
        hasQuarantineCert: appointmentData.hasQuarantineCert,
        // 导游/翻译服务专用字段
        serviceDays: appointmentData.serviceDays,
        // 咨询服务专用字段
        specificRequirements: appointmentData.specificRequirements,
        // 物流专用字段
        itemName: appointmentData.itemName,
        itemQuantity: appointmentData.itemQuantity,
        originPort: appointmentData.originPort,
        destinationPort: appointmentData.destinationPort,
        cargoName: appointmentData.cargoName,
        cargoQuantity: appointmentData.cargoQuantity,
        // 旅游规划专用字段
        travelDate: appointmentData.travelDate,
        travelDestination: appointmentData.travelDestination,
        travelDays: appointmentData.travelDays,
      });

      // Create notification for user
      await this.createAppointmentNotification(userId, appointment, 'created');

      logger.info(`Appointment created: ${appointmentNo} for user ${userId}`);

      return appointment;
    } catch (error) {
      logger.error('Error creating appointment:', error);
      throw error;
    }
  }

  /**
   * Get appointments for a user with filtering and pagination
   * @param {string} userId - User ID
   * @param {Object} options - Query options
   * @returns {Promise<Object>} - Paginated appointments
   */
  /**
   * Get user appointment statistics (counts by status)
   * @param {string} userId - User ID
   * @returns {Promise<Object>} - Appointment counts
   */
  static async getUserAppointmentStats(userId) {
    try {
      const stats = await Appointment.findAll({
        where: { userId },
        attributes: [
          'status',
          [require('sequelize').fn('COUNT', require('sequelize').col('id')), 'count'],
        ],
        group: ['status'],
        raw: true,
      });

      // 初始化统计数据
      const result = {
        total: 0,
        pending: 0,      // 预约（待处理）
        confirmed: 0,    // 已确认
        inProgress: 0,   // 进行中
        completed: 0,    // 已完成
        cancelled: 0,    // 已取消
      };

      // 填充统计数据
      stats.forEach(stat => {
        const count = parseInt(stat.count);
        result.total += count;
        if (stat.status === 'in-progress') {
          result.inProgress = count;
        } else if (result.hasOwnProperty(stat.status)) {
          result[stat.status] = count;
        }
      });

      return result;
    } catch (error) {
      logger.error('Error fetching user appointment stats:', error);
      throw error;
    }
  }

  static async getUserAppointments(userId, { page = 1, limit = 10, status } = {}) {
    try {
      const offset = (page - 1) * limit;

      const where = { userId };
      if (status) {
        where.status = status;
      }

      const { count, rows } = await Appointment.findAndCountAll({
        where,
        include: [
          {
            model: Service,
            as: 'service',
            attributes: ['id', 'titleZh', 'titleEn', 'titleEs', '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', 'service_type', 'image_url'],
          },
        ],
        order: [['createdAt', 'DESC']],
        limit: parseInt(limit),
        offset: parseInt(offset),
      });

      return {
        data: rows.map(appointment => appointment.toJSON()),
        pagination: {
          page: parseInt(page),
          limit: parseInt(limit),
          total: count,
          totalPages: Math.ceil(count / limit),
        },
      };
    } catch (error) {
      logger.error('Error fetching user appointments:', error);
      throw error;
    }
  }

  /**
   * Get appointment by ID
   * @param {string} appointmentId - Appointment ID
   * @param {string} userId - User ID (for authorization)
   * @returns {Promise<Object>} - Appointment details
   */
  static async getAppointmentById(appointmentId, userId) {
    try {
      const appointment = await Appointment.findOne({
        where: {
          id: appointmentId,
          userId, // Ensure user can only access their own appointments
        },
        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'],
              },
            ],
          },
        ],
      });

      return appointment ? appointment.toJSON() : null;
    } catch (error) {
      logger.error(`Error fetching appointment ${appointmentId}:`, error);
      throw error;
    }
  }

  /**
   * Update appointment
   * @param {string} appointmentId - Appointment ID
   * @param {string} userId - User ID (for authorization)
   * @param {Object} updateData - Data to update
   * @returns {Promise<Object>} - Updated appointment
   */
  static async updateAppointment(appointmentId, userId, updateData) {
    try {
      const appointment = await Appointment.findOne({
        where: {
          id: appointmentId,
          userId,
        },
      });

      if (!appointment) {
        throw new Error('APPOINTMENT_NOT_FOUND');
      }

      // If status is being updated, validate transition
      if (updateData.status && updateData.status !== appointment.status) {
        if (!this.isValidStatusTransition(appointment.status, updateData.status)) {
          throw new Error('INVALID_STATUS_TRANSITION');
        }
      }

      // Update appointment
      await appointment.update(updateData);

      // Create notification if status changed
      if (updateData.status && updateData.status !== appointment.status) {
        await this.createAppointmentNotification(userId, appointment, 'updated');
      }

      logger.info(`Appointment updated: ${appointment.appointmentNo}`);

      return appointment.toJSON();
    } catch (error) {
      logger.error(`Error updating appointment ${appointmentId}:`, error);
      throw error;
    }
  }

  /**
   * Cancel appointment
   * @param {string} appointmentId - Appointment ID
   * @param {string} userId - User ID (for authorization)
   * @returns {Promise<Object>} - Cancelled appointment
   */
  static async cancelAppointment(appointmentId, userId) {
    try {
      const appointment = await Appointment.findOne({
        where: {
          id: appointmentId,
          userId,
        },
      });

      if (!appointment) {
        throw new Error('APPOINTMENT_NOT_FOUND');
      }

      // Check if appointment can be cancelled
      if (appointment.status === 'completed') {
        throw new Error('CANNOT_CANCEL_COMPLETED');
      }

      if (appointment.status === 'cancelled') {
        throw new Error('ALREADY_CANCELLED');
      }

      // Validate status transition
      if (!this.isValidStatusTransition(appointment.status, 'cancelled')) {
        throw new Error('INVALID_STATUS_TRANSITION');
      }

      // Update status to cancelled
      await appointment.update({ status: 'cancelled' });

      // Create notification
      await this.createAppointmentNotification(userId, appointment, 'cancelled');

      logger.info(`Appointment cancelled: ${appointment.appointmentNo}`);

      return appointment.toJSON();
    } catch (error) {
      logger.error(`Error cancelling appointment ${appointmentId}:`, error);
      throw error;
    }
  }

  /**
   * Mark appointment as paid and process first payment reward
   * @param {string} appointmentId - Appointment ID
   * @param {string} userId - User ID (for authorization)
   * @returns {Promise<Object>} - Updated appointment
   */
  static async markAppointmentAsPaid(appointmentId, userId) {
    try {
      const appointment = await Appointment.findOne({
        where: {
          id: appointmentId,
          userId,
        },
      });

      if (!appointment) {
        throw new Error('APPOINTMENT_NOT_FOUND');
      }

      if (appointment.paidAt) {
        throw new Error('ALREADY_PAID');
      }

      // Mark as paid
      appointment.paidAt = new Date();
      await appointment.save();

      // Process first payment reward if applicable
      try {
        await invitationService.processFirstPayment(userId, appointmentId);
      } catch (error) {
        logger.error('Error processing first payment reward:', error);
        // Don't throw - reward processing failure shouldn't break payment
      }

      logger.info(`Appointment marked as paid: ${appointment.appointmentNo}`);

      return appointment.toJSON();
    } catch (error) {
      logger.error(`Error marking appointment as paid ${appointmentId}:`, error);
      throw error;
    }
  }

  /**
   * Create notification for appointment action
   * @param {string} userId - User ID
   * @param {Object} appointment - Appointment object
   * @param {string} action - Action type (created, updated, cancelled)
   */
  static async createAppointmentNotification(userId, appointment, action) {
    try {
      const titleMap = {
        created: {
          zh: '预约创建成功',
          en: 'Appointment Created',
          es: 'Cita Creada',
        },
        updated: {
          zh: '预约状态更新',
          en: 'Appointment Updated',
          es: 'Cita Actualizada',
        },
        cancelled: {
          zh: '预约已取消',
          en: 'Appointment Cancelled',
          es: 'Cita Cancelada',
        },
      };

      const contentMap = {
        created: {
          zh: `您的预约 ${appointment.appointmentNo} 已创建成功`,
          en: `Your appointment ${appointment.appointmentNo} has been created successfully`,
          es: `Su cita ${appointment.appointmentNo} ha sido creada exitosamente`,
        },
        updated: {
          zh: `您的预约 ${appointment.appointmentNo} 状态已更新为 ${appointment.status}`,
          en: `Your appointment ${appointment.appointmentNo} status has been updated to ${appointment.status}`,
          es: `El estado de su cita ${appointment.appointmentNo} ha sido actualizado a ${appointment.status}`,
        },
        cancelled: {
          zh: `您的预约 ${appointment.appointmentNo} 已取消`,
          en: `Your appointment ${appointment.appointmentNo} has been cancelled`,
          es: `Su cita ${appointment.appointmentNo} ha sido cancelada`,
        },
      };

      await Notification.create({
        userId,
        type: 'service',
        titleZh: titleMap[action].zh,
        titleEn: titleMap[action].en,
        titleEs: titleMap[action].es,
        contentZh: contentMap[action].zh,
        contentEn: contentMap[action].en,
        contentEs: contentMap[action].es,
        isRead: false,
      });
    } catch (error) {
      logger.error('Error creating appointment notification:', error);
      // Don't throw - notification failure shouldn't break appointment operations
    }
  }
}

module.exports = AppointmentService;
