const TherapistProfile = require("../../models/TherapistProfile");
const User = require("../../models/userModel");
const Appointment = require("../../models/Appointment");
const Therapy = require("../../models/Therapy");
const mongoose = require("mongoose");
const moment = require("moment");

// Intelligent therapist-client matching
const findMatchingTherapists = async (req, res) => {
  try {
    const {
      preferredMode,      // "Online", "Offline", "Hybrid"
      sessionType,        // "Individual Therapy", "Couples Therapy", etc.
      preferredDate,      // ISO date string
      preferredTime,      // "HH:MM" format
      language,           // Optional: preferred language
      specialization      // Optional: specific specialization needed
    } = req.body;

    // Validation
    if (!preferredMode || !sessionType || !preferredDate || !preferredTime) {
      return res.status(400).json({
        success: false,
        message: "Preferred mode, session type, date, and time are required"
      });
    }

    const requestedDate = new Date(preferredDate);
    if (isNaN(requestedDate.getTime())) {
      return res.status(400).json({
        success: false,
        message: "Invalid date format"
      });
    }

    // Validate time format
    const timeRegex = /^([01]\d|2[0-3]):([0-5]\d)$/;
    if (!timeRegex.test(preferredTime)) {
      return res.status(400).json({
        success: false,
        message: "Invalid time format. Use HH:MM format."
      });
    }

    // Step 1: Filter therapists based on basic criteria
    let matchQuery = {
      isActive: true,
      approvalStatus: 'approved',
      therapyModes: { $in: [preferredMode] },
      therapyTypes: { $in: [sessionType] }
    };

    // Add language filter if specified
    if (language) {
      matchQuery.languages = { $in: [language] };
    }

    // Add specialization filter if specified
    if (specialization) {
      matchQuery.specializations = { $in: [specialization] };
    }

    const potentialTherapists = await TherapistProfile.find(matchQuery)
      .populate('user', 'fullname email')
      .lean();

    if (potentialTherapists.length === 0) {
      return res.status(200).json({
        success: true,
        message: "No therapists found matching your criteria",
        data: {
          availableTherapists: [],
          suggestions: await generateAlternativeSuggestions(preferredMode, sessionType, requestedDate, preferredTime)
        }
      });
    }

    // Step 2: Check availability for each therapist
    const availableTherapists = [];
    const dayOfWeek = requestedDate.toLocaleDateString('en-US', { weekday: 'lowercase' });

    for (const therapist of potentialTherapists) {
      // Check if therapist works on this day
      const dayAvailability = therapist.weeklyAvailability[dayOfWeek];
      if (!dayAvailability || !dayAvailability.available) {
        continue;
      }

      // Check if requested time falls within available slots
      const isTimeAvailable = dayAvailability.slots.some(slot => {
        const slotStart = slot.startTime;
        const slotEnd = slot.endTime;
        
        // Calculate session end time (assuming 60-minute sessions)
        const sessionEndTime = moment(preferredTime, 'HH:mm')
          .add(60, 'minutes')
          .format('HH:mm');
        
        return preferredTime >= slotStart && sessionEndTime <= slotEnd;
      });

      if (!isTimeAvailable) {
        continue;
      }

      // Check if date is marked as unavailable
      const isDateUnavailable = therapist.unavailableDates.some(unavailableDate => {
        const unavailableDateObj = new Date(unavailableDate.date);
        return unavailableDateObj.toDateString() === requestedDate.toDateString();
      });

      if (isDateUnavailable) {
        continue;
      }

      // Step 3: Check existing appointments and session limits
      const existingAppointments = await Appointment.find({
        doctor: therapist.user._id,
        date: {
          $gte: new Date(requestedDate.setHours(0, 0, 0, 0)),
          $lte: new Date(requestedDate.setHours(23, 59, 59, 999))
        },
        status: { $in: ['scheduled', 'completed'] }
      });

      // Check if therapist has reached max sessions for the day
      if (existingAppointments.length >= therapist.maxSessionsPerDay) {
        continue;
      }

      // Check for time conflicts
      const hasConflict = existingAppointments.some(appointment => {
        const existingStart = appointment.timeSlot.startTime;
        const existingEnd = appointment.timeSlot.endTime;
        const sessionEndTime = moment(preferredTime, 'HH:mm')
          .add(60, 'minutes')
          .format('HH:mm');
        
        return (
          (preferredTime >= existingStart && preferredTime < existingEnd) ||
          (sessionEndTime > existingStart && sessionEndTime <= existingEnd) ||
          (preferredTime <= existingStart && sessionEndTime >= existingEnd)
        );
      });

      if (hasConflict) {
        continue;
      }

      // Step 4: Calculate match score for ranking
      let matchScore = 100;
      
      // Bonus for exact mode match
      if (therapist.therapyModes.includes(preferredMode)) {
        matchScore += 10;
      }
      
      // Bonus for language match
      if (language && therapist.languages && therapist.languages.includes(language)) {
        matchScore += 15;
      }
      
      // Bonus for specialization match
      if (specialization && therapist.specializations && therapist.specializations.includes(specialization)) {
        matchScore += 20;
      }
      
      // Bonus for experience
      matchScore += Math.min(therapist.yearsOfExperience * 2, 20);
      
      // Bonus for profile completion
      matchScore += (therapist.profileCompletionPercentage / 100) * 10;
      
      // Penalty for high session load
      const sessionLoadPenalty = (existingAppointments.length / therapist.maxSessionsPerDay) * 10;
      matchScore -= sessionLoadPenalty;

      availableTherapists.push({
        therapistId: therapist.user._id,
        therapistName: therapist.user.fullname,
        professionalTitle: therapist.professionalTitle,
        yearsOfExperience: therapist.yearsOfExperience,
        specializations: therapist.specializations,
        languages: therapist.languages,
        matchScore: Math.round(matchScore),
        currentSessionLoad: existingAppointments.length,
        maxSessions: therapist.maxSessionsPerDay,
        profileCompletion: therapist.profileCompletionPercentage,
        bio: therapist.bio
      });
    }

    // Sort by match score (highest first)
    availableTherapists.sort((a, b) => b.matchScore - a.matchScore);

    if (availableTherapists.length === 0) {
      return res.status(200).json({
        success: true,
        message: "No therapists available for the selected time slot",
        data: {
          availableTherapists: [],
          suggestions: await generateAlternativeSuggestions(preferredMode, sessionType, requestedDate, preferredTime)
        }
      });
    }

    return res.status(200).json({
      success: true,
      message: "Matching therapists found successfully",
      data: {
        availableTherapists: availableTherapists.slice(0, 5), // Return top 5 matches
        totalMatches: availableTherapists.length,
        requestedSlot: {
          date: preferredDate,
          time: preferredTime,
          mode: preferredMode,
          sessionType: sessionType
        }
      }
    });

  } catch (error) {
    console.error("Find matching therapists error:", error);
    return res.status(500).json({
      success: false,
      message: "Server Error",
      error: error.message
    });
  }
};

// Generate alternative suggestions when no therapists are available
const generateAlternativeSuggestions = async (preferredMode, sessionType, requestedDate, preferredTime) => {
  try {
    const suggestions = [];

    // Find therapists who match mode and session type but not time
    const therapists = await TherapistProfile.find({
      isActive: true,
      approvalStatus: 'approved',
      therapyModes: { $in: [preferredMode] },
      therapyTypes: { $in: [sessionType] }
    }).populate('user', 'fullname');

    // Suggest same day, different times
    const sameDayAlternatives = [];
    const dayOfWeek = requestedDate.toLocaleDateString('en-US', { weekday: 'lowercase' });
    
    for (const therapist of therapists) {
      const dayAvailability = therapist.weeklyAvailability[dayOfWeek];
      if (dayAvailability && dayAvailability.available) {
        // Get existing appointments for this therapist on this date
        const existingAppointments = await Appointment.find({
          doctor: therapist.user._id,
          date: {
            $gte: new Date(requestedDate.setHours(0, 0, 0, 0)),
            $lte: new Date(requestedDate.setHours(23, 59, 59, 999))
          },
          status: { $in: ['scheduled', 'completed'] }
        });

        // Find free slots
        for (const slot of dayAvailability.slots) {
          const slotStart = moment(slot.startTime, 'HH:mm');
          const slotEnd = moment(slot.endTime, 'HH:mm');
          
          // Generate 60-minute time slots
          while (slotStart.clone().add(60, 'minutes').isSameOrBefore(slotEnd)) {
            const timeSlot = slotStart.format('HH:mm');
            const endTime = slotStart.clone().add(60, 'minutes').format('HH:mm');
            
            // Check if this slot is free
            const isSlotFree = !existingAppointments.some(apt => {
              return (
                (timeSlot >= apt.timeSlot.startTime && timeSlot < apt.timeSlot.endTime) ||
                (endTime > apt.timeSlot.startTime && endTime <= apt.timeSlot.endTime)
              );
            });
            
            if (isSlotFree && timeSlot !== preferredTime) {
              sameDayAlternatives.push({
                therapistId: therapist.user._id,
                therapistName: therapist.user.fullname,
                date: requestedDate.toISOString().split('T')[0],
                time: timeSlot,
                type: 'same_day_different_time'
              });
            }
            
            slotStart.add(60, 'minutes');
          }
        }
      }
    }

    if (sameDayAlternatives.length > 0) {
      suggestions.push({
        type: 'same_day_different_time',
        title: 'Same day, different times',
        options: sameDayAlternatives.slice(0, 3)
      });
    }

    // Suggest next day, same time
    const nextDay = moment(requestedDate).add(1, 'day').toDate();
    const nextDayAlternatives = [];
    const nextDayOfWeek = nextDay.toLocaleDateString('en-US', { weekday: 'lowercase' });
    
    for (const therapist of therapists.slice(0, 3)) {
      const dayAvailability = therapist.weeklyAvailability[nextDayOfWeek];
      if (dayAvailability && dayAvailability.available) {
        const isTimeAvailable = dayAvailability.slots.some(slot => {
          const sessionEndTime = moment(preferredTime, 'HH:mm').add(60, 'minutes').format('HH:mm');
          return preferredTime >= slot.startTime && sessionEndTime <= slot.endTime;
        });
        
        if (isTimeAvailable) {
          nextDayAlternatives.push({
            therapistId: therapist.user._id,
            therapistName: therapist.user.fullname,
            date: nextDay.toISOString().split('T')[0],
            time: preferredTime,
            type: 'next_day_same_time'
          });
        }
      }
    }

    if (nextDayAlternatives.length > 0) {
      suggestions.push({
        type: 'next_day_same_time',
        title: 'Next day, same time',
        options: nextDayAlternatives
      });
    }

    // Suggest earliest available slots
    const earliestAvailable = [];
    const today = new Date();
    
    for (let i = 0; i < 7; i++) {
      const checkDate = moment(today).add(i, 'days').toDate();
      const checkDayOfWeek = checkDate.toLocaleDateString('en-US', { weekday: 'lowercase' });
      
      for (const therapist of therapists.slice(0, 2)) {
        const dayAvailability = therapist.weeklyAvailability[checkDayOfWeek];
        if (dayAvailability && dayAvailability.available && dayAvailability.slots.length > 0) {
          const earliestSlot = dayAvailability.slots[0];
          earliestAvailable.push({
            therapistId: therapist.user._id,
            therapistName: therapist.user.fullname,
            date: checkDate.toISOString().split('T')[0],
            time: earliestSlot.startTime,
            type: 'earliest_available'
          });
          break;
        }
      }
      
      if (earliestAvailable.length >= 3) break;
    }

    if (earliestAvailable.length > 0) {
      suggestions.push({
        type: 'earliest_available',
        title: 'Earliest available slots',
        options: earliestAvailable
      });
    }

    return suggestions;

  } catch (error) {
    console.error("Generate suggestions error:", error);
    return [];
  }
};

// Book appointment with selected therapist
const bookAppointmentWithTherapist = async (req, res) => {
  try {
    const userId = req.user.id;
    const {
      therapistId,
      date,
      startTime,
      sessionType,
      mode,
      notes
    } = req.body;

    // Validation
    if (!therapistId || !date || !startTime || !sessionType || !mode) {
      return res.status(400).json({
        success: false,
        message: "All booking details are required"
      });
    }

    // Validate therapist exists and is available
    const therapist = await TherapistProfile.findOne({ 
      user: therapistId, 
      isActive: true, 
      approvalStatus: 'approved' 
    });

    if (!therapist) {
      return res.status(404).json({
        success: false,
        message: "Therapist not found or not available"
      });
    }

    // Check if therapist supports the requested mode and session type
    if (!therapist.therapyModes.includes(mode) || !therapist.therapyTypes.includes(sessionType)) {
      return res.status(400).json({
        success: false,
        message: "Therapist does not support the requested therapy mode or session type"
      });
    }

    const appointmentDate = new Date(date);
    const endTime = moment(startTime, 'HH:mm').add(60, 'minutes').format('HH:mm');

    // Double-check availability (prevent double booking)
    const existingAppointment = await Appointment.findOne({
      doctor: therapistId,
      date: {
        $gte: new Date(appointmentDate.setHours(0, 0, 0, 0)),
        $lte: new Date(appointmentDate.setHours(23, 59, 59, 999))
      },
      $or: [
        {
          'timeSlot.startTime': { $lte: startTime },
          'timeSlot.endTime': { $gt: startTime }
        },
        {
          'timeSlot.startTime': { $lt: endTime },
          'timeSlot.endTime': { $gte: endTime }
        }
      ],
      status: { $in: ['scheduled', 'completed'] }
    });

    if (existingAppointment) {
      return res.status(409).json({
        success: false,
        message: "This time slot is no longer available"
      });
    }

    // Check daily session limit
    const dailyAppointments = await Appointment.countDocuments({
      doctor: therapistId,
      date: {
        $gte: new Date(appointmentDate.setHours(0, 0, 0, 0)),
        $lte: new Date(appointmentDate.setHours(23, 59, 59, 999))
      },
      status: { $in: ['scheduled', 'completed'] }
    });

    if (dailyAppointments >= therapist.maxSessionsPerDay) {
      return res.status(409).json({
        success: false,
        message: "Therapist has reached maximum sessions for this day"
      });
    }

    // Create the appointment
    const appointment = new Appointment({
      date: appointmentDate,
      timeSlot: {
        startTime: startTime,
        endTime: endTime
      },
      doctor: therapistId,
      patient: userId,
      status: 'scheduled',
      notes: notes || null
    });

    await appointment.save();

    // Populate the appointment with user details
    await appointment.populate([
      { path: 'doctor', select: 'fullname email' },
      { path: 'patient', select: 'fullname email mobile' }
    ]);

    return res.status(201).json({
      success: true,
      message: "Appointment booked successfully",
      data: {
        appointmentId: appointment._id,
        therapist: appointment.doctor,
        patient: appointment.patient,
        date: appointment.date,
        timeSlot: appointment.timeSlot,
        sessionType: sessionType,
        mode: mode,
        status: appointment.status
      }
    });

  } catch (error) {
    console.error("Book appointment error:", error);
    return res.status(500).json({
      success: false,
      message: "Server Error",
      error: error.message
    });
  }
};

// Get therapist availability for multiple days (for calendar view)
const getTherapistAvailabilityCalendar = async (req, res) => {
  try {
    const { therapistId, startDate, endDate } = req.query;

    if (!therapistId || !startDate || !endDate) {
      return res.status(400).json({
        success: false,
        message: "Therapist ID, start date, and end date are required"
      });
    }

    const therapist = await TherapistProfile.findOne({ 
      user: therapistId, 
      isActive: true, 
      approvalStatus: 'approved' 
    });

    if (!therapist) {
      return res.status(404).json({
        success: false,
        message: "Therapist not found"
      });
    }

    const start = new Date(startDate);
    const end = new Date(endDate);
    const calendar = [];

    // Get all appointments in the date range
    const appointments = await Appointment.find({
      doctor: therapistId,
      date: { $gte: start, $lte: end },
      status: { $in: ['scheduled', 'completed'] }
    });

    // Generate calendar for each day
    for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
      const currentDate = new Date(d);
      const dayOfWeek = currentDate.toLocaleDateString('en-US', { weekday: 'lowercase' });
      const dayAvailability = therapist.weeklyAvailability[dayOfWeek];
      
      // Check if date is marked as unavailable
      const isUnavailable = therapist.unavailableDates.some(unavailableDate => {
        const unavailableDateObj = new Date(unavailableDate.date);
        return unavailableDateObj.toDateString() === currentDate.toDateString();
      });

      const dayAppointments = appointments.filter(apt => {
        return apt.date.toDateString() === currentDate.toDateString();
      });

      let availableSlots = [];
      if (dayAvailability && dayAvailability.available && !isUnavailable) {
        // Generate all possible slots
        for (const slot of dayAvailability.slots) {
          const slotStart = moment(slot.startTime, 'HH:mm');
          const slotEnd = moment(slot.endTime, 'HH:mm');
          
          while (slotStart.clone().add(60, 'minutes').isSameOrBefore(slotEnd)) {
            const timeSlot = slotStart.format('HH:mm');
            const endTime = slotStart.clone().add(60, 'minutes').format('HH:mm');
            
            // Check if this slot is free
            const isSlotFree = !dayAppointments.some(apt => {
              return (
                (timeSlot >= apt.timeSlot.startTime && timeSlot < apt.timeSlot.endTime) ||
                (endTime > apt.timeSlot.startTime && endTime <= apt.timeSlot.endTime)
              );
            });
            
            availableSlots.push({
              startTime: timeSlot,
              endTime: endTime,
              available: isSlotFree
            });
            
            slotStart.add(60, 'minutes');
          }
        }
      }

      calendar.push({
        date: currentDate.toISOString().split('T')[0],
        dayOfWeek: dayOfWeek,
        isAvailable: !isUnavailable && dayAvailability?.available,
        totalSlots: availableSlots.length,
        availableSlots: availableSlots.filter(slot => slot.available),
        bookedSlots: dayAppointments.map(apt => ({
          startTime: apt.timeSlot.startTime,
          endTime: apt.timeSlot.endTime,
          appointmentId: apt._id
        })),
        sessionCount: dayAppointments.length,
        maxSessions: therapist.maxSessionsPerDay
      });
    }

    return res.status(200).json({
      success: true,
      message: "Therapist calendar fetched successfully",
      data: {
        therapistId: therapistId,
        calendar: calendar,
        therapistInfo: {
          name: therapist.fullName,
          title: therapist.professionalTitle,
          maxSessionsPerDay: therapist.maxSessionsPerDay,
          breakDuration: therapist.breakDurationMinutes
        }
      }
    });

  } catch (error) {
    console.error("Get therapist calendar error:", error);
    return res.status(500).json({
      success: false,
      message: "Server Error",
      error: error.message
    });
  }
};

module.exports = {
  findMatchingTherapists,
  bookAppointmentWithTherapist,
  getTherapistAvailabilityCalendar
};
