const mongoose = require("mongoose");

const availabilityNotificationSchema = new mongoose.Schema({
  // Who the notification is for
  recipient: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "User",
    required: true,
    index: true
  },
  
  // Who triggered the notification
  sender: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "User",
    required: true
  },
  
  // Type of notification
  type: {
    type: String,
    enum: [
      "availability_change_pending",
      "availability_change_approved", 
      "availability_change_rejected",
      "availability_reminder",
      "conflict_detected",
      "booking_on_pending_slot",
      "admin_approval_required"
    ],
    required: true
  },
  
  // Notification title and message
  title: {
    type: String,
    required: true,
    maxlength: 200
  },
  
  message: {
    type: String,
    required: true,
    maxlength: 1000
  },
  
  // Related data
  relatedData: {
    // Therapist availability ID
    availabilityId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "TherapistAvailability",
      default: null
    },
    
    // Pending change ID
    pendingChangeId: {
      type: mongoose.Schema.Types.ObjectId,
      default: null
    },
    
    // Appointment ID (if related to booking)
    appointmentId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Appointment",
      default: null
    },
    
    // Date related to the change
    relatedDate: {
      type: Date,
      default: null
    },
    
    // Time slots involved
    timeSlots: [{
      startTime: String,
      endTime: String
    }],
    
    // Additional context data
    metadata: {
      type: mongoose.Schema.Types.Mixed,
      default: {}
    }
  },
  
  // Notification status
  status: {
    type: String,
    enum: ["unread", "read", "archived"],
    default: "unread"
  },
  
  // Priority level
  priority: {
    type: String,
    enum: ["low", "medium", "high", "urgent"],
    default: "medium"
  },
  
  // Action required
  actionRequired: {
    type: Boolean,
    default: false
  },
  
  // Available actions for the notification
  actions: [{
    type: {
      type: String,
      enum: ["approve", "reject", "view", "reschedule", "acknowledge"],
      required: true
    },
    label: {
      type: String,
      required: true
    },
    url: {
      type: String,
      default: null
    }
  }],
  
  // Read timestamp
  readAt: {
    type: Date,
    default: null
  },
  
  // Expiry date for the notification
  expiresAt: {
    type: Date,
    default: null
  },
  
  // Auto-generated flag
  isAutoGenerated: {
    type: Boolean,
    default: true
  }
}, { 
  timestamps: true,
  toJSON: { virtuals: true },
  toObject: { virtuals: true }
});

// Indexes for better performance
availabilityNotificationSchema.index({ recipient: 1, status: 1 });
availabilityNotificationSchema.index({ type: 1 });
availabilityNotificationSchema.index({ createdAt: -1 });
availabilityNotificationSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });

// Virtual for checking if notification is expired
availabilityNotificationSchema.virtual('isExpired').get(function() {
  return this.expiresAt && this.expiresAt < new Date();
});

// Method to mark as read
availabilityNotificationSchema.methods.markAsRead = function() {
  this.status = 'read';
  this.readAt = new Date();
  return this.save();
};

// Method to archive notification
availabilityNotificationSchema.methods.archive = function() {
  this.status = 'archived';
  return this.save();
};

// Static method to create availability change notification
availabilityNotificationSchema.statics.createAvailabilityChangeNotification = async function(data) {
  const {
    recipientId,
    senderId,
    type,
    availabilityId,
    pendingChangeId,
    timeSlots = [],
    relatedDate,
    metadata = {}
  } = data;
  
  let title, message, actions = [], priority = 'medium';
  
  switch (type) {
    case 'availability_change_pending':
      title = 'Availability Change Pending Approval';
      message = `A therapist has requested changes to their availability schedule. Please review and approve.`;
      actions = [
        { type: 'view', label: 'Review Changes', url: `/admin/availability-approvals/${pendingChangeId}` },
        { type: 'approve', label: 'Approve' },
        { type: 'reject', label: 'Reject' }
      ];
      priority = 'high';
      break;
      
    case 'availability_change_approved':
      title = 'Availability Changes Approved';
      message = `Your availability changes have been approved and are now live on the platform.`;
      actions = [
        { type: 'view', label: 'View Schedule', url: '/therapist/availability' }
      ];
      break;
      
    case 'availability_change_rejected':
      title = 'Availability Changes Rejected';
      message = `Your availability changes have been rejected. Please review the feedback and resubmit if needed.`;
      actions = [
        { type: 'view', label: 'View Feedback', url: '/therapist/availability' }
      ];
      priority = 'high';
      break;
      
    case 'availability_reminder':
      title = 'Update Your Availability';
      message = `You haven't set your availability for next week. Please update your schedule to stay visible to clients.`;
      actions = [
        { type: 'view', label: 'Update Availability', url: '/therapist/availability' }
      ];
      break;
      
    case 'conflict_detected':
      title = 'Schedule Conflict Detected';
      message = `A conflict has been detected in your availability schedule. Please review and resolve.`;
      actions = [
        { type: 'view', label: 'Resolve Conflict', url: '/therapist/availability' }
      ];
      priority = 'urgent';
      break;
      
    case 'booking_on_pending_slot':
      title = 'Booking on Pending Slot';
      message = `A client has booked a session on a time slot that is still pending approval.`;
      actions = [
        { type: 'view', label: 'View Booking', url: '/therapist/appointments' }
      ];
      priority = 'high';
      break;
      
    default:
      title = 'Availability Notification';
      message = 'You have a new availability-related notification.';
  }
  
  const notification = new this({
    recipient: recipientId,
    sender: senderId,
    type,
    title,
    message,
    relatedData: {
      availabilityId,
      pendingChangeId,
      relatedDate,
      timeSlots,
      metadata
    },
    actions,
    priority,
    actionRequired: ['availability_change_pending', 'conflict_detected'].includes(type),
    expiresAt: type === 'availability_reminder' ? new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) : null // 7 days for reminders
  });
  
  return await notification.save();
};

// Static method to get unread notifications for user
availabilityNotificationSchema.statics.getUnreadForUser = async function(userId) {
  return await this.find({
    recipient: userId,
    status: 'unread'
  })
  .populate('sender', 'fullname email')
  .sort({ createdAt: -1 });
};

// Static method to get notifications requiring action
availabilityNotificationSchema.statics.getActionRequiredForUser = async function(userId) {
  return await this.find({
    recipient: userId,
    actionRequired: true,
    status: { $ne: 'archived' }
  })
  .populate('sender', 'fullname email')
  .sort({ priority: -1, createdAt: -1 });
};

module.exports = mongoose.model("AvailabilityNotification", availabilityNotificationSchema);
