const TherapistAvailability = require("../../models/TherapistAvailability");
const AvailabilityNotification = require("../../models/AvailabilityNotification");
const User = require("../../models/userModel");
const Appointment = require("../../models/Appointment");
const mongoose = require("mongoose");

// Get all pending availability changes for admin review
const getPendingAvailabilityChanges = async (req, res) => {
  try {
    const { page = 1, limit = 10, therapistId, changeType } = req.query;
    
    const filter = {
      'pendingChanges.status': 'pending'
    };
    
    if (therapistId) {
      filter.therapist = therapistId;
    }
    
    const availabilities = await TherapistAvailability.find(filter)
      .populate('therapist', 'fullname email')
      .populate('pendingChanges.adminResponse.approvedBy', 'fullname email')
      .sort({ 'pendingChanges.requestedAt': -1 })
      .limit(limit * 1)
      .skip((page - 1) * limit);
    
    // Extract pending changes
    const pendingChanges = [];
    availabilities.forEach(availability => {
      availability.pendingChanges.forEach(change => {
        if (change.status === 'pending') {
          if (!changeType || change.changeType === changeType) {
            pendingChanges.push({
              _id: change._id,
              availabilityId: availability._id,
              therapist: availability.therapist,
              changeType: change.changeType,
              changeData: change.changeData,
              reason: change.reason,
              requestedAt: change.requestedAt,
              status: change.status
            });
          }
        }
      });
    });
    
    // Sort by requested date
    pendingChanges.sort((a, b) => new Date(b.requestedAt) - new Date(a.requestedAt));
    
    const total = pendingChanges.length;
    const paginatedChanges = pendingChanges.slice((page - 1) * limit, page * limit);
    
    return res.status(200).json({
      success: true,
      message: "Pending changes fetched successfully",
      data: {
        changes: paginatedChanges,
        pagination: {
          currentPage: parseInt(page),
          totalPages: Math.ceil(total / limit),
          totalItems: total,
          itemsPerPage: parseInt(limit)
        }
      }
    });
    
  } catch (error) {
    console.error("Get pending changes error:", error);
    return res.status(500).json({
      success: false,
      message: "Server Error",
      error: error.message
    });
  }
};

// Get specific availability change details for review
const getAvailabilityChangeDetails = async (req, res) => {
  try {
    const { availabilityId, changeId } = req.params;
    
    const availability = await TherapistAvailability.findById(availabilityId)
      .populate('therapist', 'fullname email mobile')
      .populate('pendingChanges.adminResponse.approvedBy', 'fullname email');
    
    if (!availability) {
      return res.status(404).json({
        success: false,
        message: "Availability record not found"
      });
    }
    
    const change = availability.pendingChanges.id(changeId);
    
    if (!change) {
      return res.status(404).json({
        success: false,
        message: "Change request not found"
      });
    }
    
    // Get potential conflicts if this change is approved
    let conflicts = [];
    if (change.changeType === 'modify_slots') {
      conflicts = await checkChangeConflicts(availability.therapist._id, change.changeData);
    }
    
    // Get therapist's current appointment count and booking patterns
    const stats = await getTherapistStats(availability.therapist._id);
    
    return res.status(200).json({
      success: true,
      message: "Change details fetched successfully",
      data: {
        availability,
        change,
        conflicts,
        therapistStats: stats
      }
    });
    
  } catch (error) {
    console.error("Get change details error:", error);
    return res.status(500).json({
      success: false,
      message: "Server Error",
      error: error.message
    });
  }
};

// Approve availability change
const approveAvailabilityChange = async (req, res) => {
  try {
    const { availabilityId, changeId } = req.params;
    const { feedback } = req.body;
    const adminId = req.user.id;
    
    const availability = await TherapistAvailability.findById(availabilityId);
    
    if (!availability) {
      return res.status(404).json({
        success: false,
        message: "Availability record not found"
      });
    }
    
    const change = availability.pendingChanges.id(changeId);
    
    if (!change) {
      return res.status(404).json({
        success: false,
        message: "Change request not found"
      });
    }
    
    if (change.status !== 'pending') {
      return res.status(400).json({
        success: false,
        message: "Change request is not pending"
      });
    }
    
    // Apply the change based on type
    switch (change.changeType) {
      case 'modify_slots':
        availability.weeklyAvailability = change.changeData.weeklyAvailability;
        // Update all slots to live status
        availability.weeklyAvailability.forEach(day => {
          day.slots.forEach(slot => {
            slot.status = 'live';
            slot.approvalStatus = 'approved';
            slot.approvedBy = adminId;
            slot.approvedAt = new Date();
          });
        });
        break;
        
      case 'add_slots':
        if (change.changeData.oneTimeSlot) {
          const newSlot = {
            ...change.changeData.oneTimeSlot,
            status: 'live',
            approvalStatus: 'approved',
            approvedBy: adminId,
            approvedAt: new Date()
          };
          availability.oneTimeSlots.push(newSlot);
        }
        break;
        
      case 'add_unavailable_date':
        change.changeData.unavailableDates.forEach(unavailableDate => {
          availability.unavailableDates.push({
            ...unavailableDate,
            approvalStatus: 'approved',
            approvedBy: adminId
          });
        });
        break;
        
      case 'modify_settings':
        availability.settings = { ...availability.settings, ...change.changeData.settings };
        break;
    }
    
    // Update change status
    change.status = 'approved';
    change.adminResponse = {
      approvedBy: adminId,
      responseAt: new Date(),
      feedback: feedback || 'Approved'
    };
    
    await availability.save();
    
    // Create notification for therapist
    await AvailabilityNotification.createAvailabilityChangeNotification({
      recipientId: availability.therapist,
      senderId: adminId,
      type: 'availability_change_approved',
      availabilityId: availability._id,
      pendingChangeId: changeId,
      metadata: { 
        changeType: change.changeType,
        adminFeedback: feedback
      }
    });
    
    // Update analytics
    availability.analytics.lastUpdated = new Date();
    await availability.save();
    
    return res.status(200).json({
      success: true,
      message: "Availability change approved successfully",
      data: {
        changeId,
        status: 'approved',
        approvedAt: new Date()
      }
    });
    
  } catch (error) {
    console.error("Approve change error:", error);
    return res.status(500).json({
      success: false,
      message: "Server Error",
      error: error.message
    });
  }
};

// Reject availability change
const rejectAvailabilityChange = async (req, res) => {
  try {
    const { availabilityId, changeId } = req.params;
    const { feedback, reason } = req.body;
    const adminId = req.user.id;
    
    if (!feedback) {
      return res.status(400).json({
        success: false,
        message: "Feedback is required for rejection"
      });
    }
    
    const availability = await TherapistAvailability.findById(availabilityId);
    
    if (!availability) {
      return res.status(404).json({
        success: false,
        message: "Availability record not found"
      });
    }
    
    const change = availability.pendingChanges.id(changeId);
    
    if (!change) {
      return res.status(404).json({
        success: false,
        message: "Change request not found"
      });
    }
    
    if (change.status !== 'pending') {
      return res.status(400).json({
        success: false,
        message: "Change request is not pending"
      });
    }
    
    // Update change status
    change.status = 'rejected';
    change.adminResponse = {
      approvedBy: adminId,
      responseAt: new Date(),
      feedback: feedback
    };
    
    await availability.save();
    
    // Create notification for therapist
    await AvailabilityNotification.createAvailabilityChangeNotification({
      recipientId: availability.therapist,
      senderId: adminId,
      type: 'availability_change_rejected',
      availabilityId: availability._id,
      pendingChangeId: changeId,
      metadata: { 
        changeType: change.changeType,
        adminFeedback: feedback,
        rejectionReason: reason
      }
    });
    
    return res.status(200).json({
      success: true,
      message: "Availability change rejected",
      data: {
        changeId,
        status: 'rejected',
        rejectedAt: new Date(),
        feedback
      }
    });
    
  } catch (error) {
    console.error("Reject change error:", error);
    return res.status(500).json({
      success: false,
      message: "Server Error",
      error: error.message
    });
  }
};

// Bulk approve multiple changes
const bulkApproveChanges = async (req, res) => {
  try {
    const { changeIds, feedback } = req.body;
    const adminId = req.user.id;
    
    if (!Array.isArray(changeIds) || changeIds.length === 0) {
      return res.status(400).json({
        success: false,
        message: "Change IDs array is required"
      });
    }
    
    const results = [];
    const errors = [];
    
    for (const changeId of changeIds) {
      try {
        // Find the availability record containing this change
        const availability = await TherapistAvailability.findOne({
          'pendingChanges._id': changeId
        });
        
        if (!availability) {
          errors.push({ changeId, error: 'Availability record not found' });
          continue;
        }
        
        const change = availability.pendingChanges.id(changeId);
        
        if (!change || change.status !== 'pending') {
          errors.push({ changeId, error: 'Change not found or not pending' });
          continue;
        }
        
        // Apply the change (simplified for bulk operation)
        switch (change.changeType) {
          case 'modify_slots':
            availability.weeklyAvailability = change.changeData.weeklyAvailability;
            availability.weeklyAvailability.forEach(day => {
              day.slots.forEach(slot => {
                slot.status = 'live';
                slot.approvalStatus = 'approved';
                slot.approvedBy = adminId;
                slot.approvedAt = new Date();
              });
            });
            break;
            
          case 'add_slots':
            if (change.changeData.oneTimeSlot) {
              const newSlot = {
                ...change.changeData.oneTimeSlot,
                status: 'live',
                approvalStatus: 'approved',
                approvedBy: adminId,
                approvedAt: new Date()
              };
              availability.oneTimeSlots.push(newSlot);
            }
            break;
            
          case 'add_unavailable_date':
            change.changeData.unavailableDates.forEach(unavailableDate => {
              availability.unavailableDates.push({
                ...unavailableDate,
                approvalStatus: 'approved',
                approvedBy: adminId
              });
            });
            break;
        }
        
        // Update change status
        change.status = 'approved';
        change.adminResponse = {
          approvedBy: adminId,
          responseAt: new Date(),
          feedback: feedback || 'Bulk approved'
        };
        
        await availability.save();
        
        // Create notification for therapist
        await AvailabilityNotification.createAvailabilityChangeNotification({
          recipientId: availability.therapist,
          senderId: adminId,
          type: 'availability_change_approved',
          availabilityId: availability._id,
          pendingChangeId: changeId,
          metadata: { 
            changeType: change.changeType,
            adminFeedback: feedback,
            bulkApproval: true
          }
        });
        
        results.push({ changeId, status: 'approved' });
        
      } catch (error) {
        errors.push({ changeId, error: error.message });
      }
    }
    
    return res.status(200).json({
      success: true,
      message: `Bulk approval completed. ${results.length} approved, ${errors.length} failed.`,
      data: {
        approved: results,
        errors: errors
      }
    });
    
  } catch (error) {
    console.error("Bulk approve error:", error);
    return res.status(500).json({
      success: false,
      message: "Server Error",
      error: error.message
    });
  }
};

// Get availability approval statistics
const getAvailabilityApprovalStats = async (req, res) => {
  try {
    const { startDate, endDate } = req.query;
    
    let dateFilter = {};
    if (startDate && endDate) {
      dateFilter = {
        'pendingChanges.requestedAt': {
          $gte: new Date(startDate),
          $lte: new Date(endDate)
        }
      };
    }
    
    const stats = await TherapistAvailability.aggregate([
      { $match: dateFilter },
      { $unwind: '$pendingChanges' },
      {
        $group: {
          _id: '$pendingChanges.status',
          count: { $sum: 1 },
          avgResponseTime: {
            $avg: {
              $cond: [
                { $ne: ['$pendingChanges.adminResponse.responseAt', null] },
                {
                  $subtract: [
                    '$pendingChanges.adminResponse.responseAt',
                    '$pendingChanges.requestedAt'
                  ]
                },
                null
              ]
            }
          }
        }
      }
    ]);
    
    // Get therapist activity stats
    const therapistStats = await TherapistAvailability.aggregate([
      {
        $group: {
          _id: null,
          totalTherapists: { $sum: 1 },
          activeTherapists: {
            $sum: {
              $cond: [
                { $gt: [{ $size: '$weeklyAvailability' }, 0] },
                1,
                0
              ]
            }
          },
          avgSlotsPerTherapist: {
            $avg: {
              $sum: {
                $map: {
                  input: '$weeklyAvailability',
                  as: 'day',
                  in: { $size: '$$day.slots' }
                }
              }
            }
          }
        }
      }
    ]);
    
    // Get pending changes by type
    const changeTypeStats = await TherapistAvailability.aggregate([
      { $unwind: '$pendingChanges' },
      { $match: { 'pendingChanges.status': 'pending' } },
      {
        $group: {
          _id: '$pendingChanges.changeType',
          count: { $sum: 1 }
        }
      }
    ]);
    
    return res.status(200).json({
      success: true,
      message: "Approval statistics fetched successfully",
      data: {
        approvalStats: stats,
        therapistStats: therapistStats[0] || {},
        changeTypeStats,
        dateRange: { startDate, endDate }
      }
    });
    
  } catch (error) {
    console.error("Get approval stats error:", error);
    return res.status(500).json({
      success: false,
      message: "Server Error",
      error: error.message
    });
  }
};

// Helper function to check conflicts
const checkChangeConflicts = async (therapistId, changeData) => {
  const conflicts = [];
  
  if (changeData.weeklyAvailability) {
    // Get appointments for next 30 days
    const startDate = new Date();
    const endDate = new Date();
    endDate.setDate(endDate.getDate() + 30);
    
    const appointments = await Appointment.find({
      doctor: therapistId,
      date: { $gte: startDate, $lte: endDate },
      status: { $in: ['scheduled', 'completed'] }
    }).populate('patient', 'fullname email');
    
    for (const appointment of appointments) {
      const dayOfWeek = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'][appointment.date.getDay()];
      const dayAvailability = changeData.weeklyAvailability.find(day => day.dayOfWeek === dayOfWeek);
      
      if (!dayAvailability || !dayAvailability.isAvailable) {
        conflicts.push({
          type: 'appointment_conflict',
          appointmentId: appointment._id,
          date: appointment.date,
          timeSlot: appointment.timeSlot,
          patient: appointment.patient,
          reason: 'Day will be marked as unavailable'
        });
        continue;
      }
      
      const slotExists = dayAvailability.slots.some(slot => 
        slot.startTime === appointment.timeSlot.startTime &&
        slot.endTime === appointment.timeSlot.endTime
      );
      
      if (!slotExists) {
        conflicts.push({
          type: 'slot_conflict',
          appointmentId: appointment._id,
          date: appointment.date,
          timeSlot: appointment.timeSlot,
          patient: appointment.patient,
          reason: 'Time slot will be removed'
        });
      }
    }
  }
  
  return conflicts;
};

// Helper function to get therapist statistics
const getTherapistStats = async (therapistId) => {
  const now = new Date();
  const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
  
  const [appointmentStats, availabilityStats] = await Promise.all([
    Appointment.aggregate([
      {
        $match: {
          doctor: new mongoose.Types.ObjectId(therapistId),
          date: { $gte: thirtyDaysAgo }
        }
      },
      {
        $group: {
          _id: null,
          totalAppointments: { $sum: 1 },
          completedAppointments: {
            $sum: { $cond: [{ $eq: ['$status', 'completed'] }, 1, 0] }
          },
          cancelledAppointments: {
            $sum: { $cond: [{ $eq: ['$status', 'cancelled'] }, 1, 0] }
          }
        }
      }
    ]),
    
    TherapistAvailability.findOne({ therapist: therapistId })
  ]);
  
  const stats = appointmentStats[0] || {
    totalAppointments: 0,
    completedAppointments: 0,
    cancelledAppointments: 0
  };
  
  // Calculate total available slots
  let totalSlots = 0;
  if (availabilityStats && availabilityStats.weeklyAvailability) {
    availabilityStats.weeklyAvailability.forEach(day => {
      if (day.isAvailable && !day.isUnavailable) {
        totalSlots += day.slots.filter(slot => slot.status === 'live').length;
      }
    });
  }
  
  return {
    ...stats,
    totalAvailableSlots: totalSlots,
    bookingRate: totalSlots > 0 ? (stats.totalAppointments / (totalSlots * 4)) * 100 : 0, // Assuming 4 weeks
    completionRate: stats.totalAppointments > 0 ? (stats.completedAppointments / stats.totalAppointments) * 100 : 0
  };
};

module.exports = {
  getPendingAvailabilityChanges,
  getAvailabilityChangeDetails,
  approveAvailabilityChange,
  rejectAvailabilityChange,
  bulkApproveChanges,
  getAvailabilityApprovalStats
};
