const DoctorTimeSlot = require("../../models/TimeSlot");
const Appointment = require("../../models/Appointment");
const User = require("../../models/userModel");
const sendMessage = require("../../utils/sendMessage");
// const { sendAppointmentConfirmation } = require("../../utils/mendingMindTemplates");
const AppointmentFeedback = require("../../models/AppointmentFeedback");
const Razorpay = require("razorpay");
const Payment = require("../../models/payment");
const mongoose = require("mongoose");
const validateInstallmentsBeforeBooking = require("../../utils/bundleCheck");
const { generateMeetLinkForAppointment } = require("../../utils/googleMeet");

const addOrUpdateTimeSlots = async (req, res) => {
  try {
    const doctorId = req.user.id;
    const { slots } = req.body;
    console.log(req.user);
    // 1. Validate input (each slot must have valid startTime and endTime)
    if (!Array.isArray(slots) || slots.length === 0) {
      return res
        .status(400)
        .json({ message: "At least one slot is required." });
    }
    for (const slot of slots) {
      if (
        !slot.startTime ||
        !slot.endTime ||
        !/^([01]\d|2[0-3]):([0-5]\d)$/.test(slot.startTime) ||
        !/^([01]\d|2[0-3]):([0-5]\d)$/.test(slot.endTime)
      ) {
        return res.status(400).json({
          message:
            "Each slot must have valid startTime and endTime in HH:mm format.",
        });
      }
    }

    // 2. Upsert: If slots already exist for doctor, update; else, create new
    const updated = await DoctorTimeSlot.findOneAndUpdate(
      { doctor: doctorId },
      { $set: { slots } },
      { upsert: true, new: true }
    );

    return res.status(200).json({
      message: "Time slots saved successfully.",
      data: updated,
    });
  } catch (error) {
    console.error("Error saving time slots:", error);
    return res.status(500).json({
      message: "An error occurred while saving time slots.",
      error: error.message,
    });
  }
};

function generateThirtyMinSlotsWithBreaks(start = "08:00", end = "24:00") {
  const slots = [];
  let [h, m] = start.split(":").map(Number);
  const [endH, endM] = end.split(":").map(Number);

  function timeToStr(h, m) {
    return `${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}`;
  }

  while (h < endH || (h === endH && m <= endM)) {
    const slotStart = timeToStr(h, m);

    // Calculate slot end
    let slotEndH = h,
      slotEndM = m + 30;
    if (slotEndM >= 60) {
      slotEndH += 1;
      slotEndM -= 60;
    }
    const slotEnd = timeToStr(slotEndH, slotEndM);

    // If the slot ends after the working hours, stop
    if (slotEndH > endH || (slotEndH === endH && slotEndM > endM)) {
      break;
    }

    slots.push({ startTime: slotStart, endTime: slotEnd });

    // Add 30-minute break
    let breakH = slotEndH,
      breakM = slotEndM + 30;
    if (breakM >= 60) {
      breakH += 1;
      breakM -= 60;
    }
    h = breakH;
    m = breakM;
  }
  return slots;
}

// Controller to get all possible 30-min slots with breaks
const getThirtyMinSlotsWithBreaks = (req, res) => {
  const { dayStart = "08:00", dayEnd = "22:00" } = req.query;
  const slots = generateThirtyMinSlotsWithBreaks(dayStart, dayEnd);

  res.status(200).json({
    message: "Available 30-minute slots with 30-minute breaks",
    slots,
  });
};

const getAvailableSlots = async (req, res) => {
  try {
    const { date, founder } = req.query;

    if (!date || !date.match(/^\d{4}-\d{2}-\d{2}$/)) {
      return res.status(400).json({
        message: "Valid date is required in 'YYYY-MM-DD' format.",
      });
    }

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

    // Check if the query date is today
    const now = new Date();
    const isToday = queryDate.toDateString() === now.toDateString();
    const currentTime = isToday ? now.toTimeString().slice(0, 5) : null; // e.g., "14:30"

    // Check if founder mode is requested
    const isFounderMode = founder === "true";
    const doctorFilter = isFounderMode
      ? { doctor: process.env.FOUNDER_DOCTOR_ID }
      : {};

    const [doctorSlotsDocs, appointments] = await Promise.all([
      DoctorTimeSlot.find(doctorFilter)
        .select("doctor slots")
        .populate("doctor", "fullname email")
        .lean(),

      Appointment.find({
        date: queryDate,
        status: { $in: ["scheduled", "completed"] },
        ...(isFounderMode && { doctor: process.env.FOUNDER_DOCTOR_ID }),
      })
        .select("doctor timeSlot")
        .lean(),
    ]);

    const bookedSlotMap = new Map();
    appointments.forEach((app) => {
      const key = `${app.doctor.toString()}_${app.timeSlot.startTime}-${
        app.timeSlot.endTime
      }`;
      bookedSlotMap.set(key, true);
    });

    const slotMap = new Map();

    doctorSlotsDocs.forEach((doc) => {
      if (!doc.doctor) return;

      doc.slots.forEach((slot) => {
        const slotKey = `${slot.startTime}-${slot.endTime}`;
        const bookingKey = `${doc.doctor._id.toString()}_${slotKey}`;

        // Skip booked slots
        if (bookedSlotMap.has(bookingKey)) return;

        // Skip past slots if the date is today
        if (isToday && slot.startTime < currentTime) return;

        if (!slotMap.has(slotKey)) {
          slotMap.set(slotKey, {
            startTime: slot.startTime,
            endTime: slot.endTime,
            doctors: [],
          });
        }

        slotMap.get(slotKey).doctors.push({
          doctorId: doc.doctor._id,
          name: doc.doctor.fullname,
          email: doc.doctor.email,
        });
      });
    });

    const availableSlots = Array.from(slotMap.values());

    return res.status(200).json({
      date,
      founder: isFounderMode,
      availableSlots,
      count: availableSlots.length,
    });
  } catch (error) {
    console.error("Error fetching available slots:", error);
    return res.status(500).json({
      message: "An error occurred while fetching available slots.",
      error:
        process.env.NODE_ENV === "production" ? "Server error" : error.message,
    });
  }
};

// const getAvailableSlots = async (req, res) => {
//   try {
//     const { date, founder } = req.query;

//     if (!date || !date.match(/^\d{4}-\d{2}-\d{2}$/)) {
//       return res.status(400).json({
//         message: "Valid date is required in 'YYYY-MM-DD' format.",
//       });
//     }

//     const queryDate = new Date(date);
//     if (isNaN(queryDate.getTime())) {
//       return res.status(400).json({ message: "Invalid date format." });
//     }

//     // Check if the query date is today
//     const now = new Date();
//     const isToday = queryDate.toDateString() === now.toDateString();
//     const currentTime = isToday ? now.toTimeString().slice(0, 5) : null; // e.g., "14:30"

//     // Check if founder mode is requested
//     const isFounderMode = founder === "true";
//     const doctorFilter = isFounderMode
//       ? { doctor: process.env.FOUNDER_DOCTOR_ID }
//       : {};

//     const [doctorSlotsDocs, appointments] = await Promise.all([
//       DoctorTimeSlot.find(doctorFilter)
//         .select("doctor slots")
//         .populate("doctor", "fullname email")
//         .lean(),

//       Appointment.find({
//         date: queryDate,
//         status: { $in: ["scheduled", "completed"] },
//         ...(isFounderMode && { doctor: process.env.FOUNDER_DOCTOR_ID }),
//       })
//         .select("doctor timeSlot")
//         .lean(),
//     ]);

//     const bookedSlotMap = new Map();
//     appointments.forEach((app) => {
//       const key = `${app.doctor.toString()}_${app.timeSlot.startTime}-${
//         app.timeSlot.endTime
//       }`;
//       bookedSlotMap.set(key, true);
//     });

//     const slotMap = new Map();

//     doctorSlotsDocs.forEach((doc) => {
//       if (!doc.doctor) return;

//       doc.slots.forEach((slot) => {
//         const slotKey = `${slot.startTime}-${slot.endTime}`;
//         const bookingKey = `${doc.doctor._id.toString()}_${slotKey}`;

//         // Skip booked slots
//         if (bookedSlotMap.has(bookingKey)) return;

//         // Skip past slots if the date is today
//         if (isToday && slot.startTime < currentTime) return;

//         if (!slotMap.has(slotKey)) {
//           slotMap.set(slotKey, {
//             startTime: slot.startTime,
//             endTime: slot.endTime,
//             doctors: [],
//           });
//         }

//         slotMap.get(slotKey).doctors.push({
//           doctorId: doc.doctor._id,
//           name: doc.doctor.fullname,
//           email: doc.doctor.email,
//         });
//       });
//     });

//     const availableSlots = Array.from(slotMap.values());

//     return res.status(200).json({
//       date,
//       founder: isFounderMode,
//       availableSlots,
//       count: availableSlots.length,
//     });
//   } catch (error) {
//     console.error("Error fetching available slots:", error);
//     return res.status(500).json({
//       message: "An error occurred while fetching available slots.",
//       error:
//         process.env.NODE_ENV === "production" ? "Server error" : error.message,
//     });
//   }
// };

// const getAvailableSlots = async (req, res) => {
//   try {
//     const { date, founder } = req.query;

//     if (!date || !date.match(/^\d{4}-\d{2}-\d{2}$/)) {
//       return res.status(400).json({
//         message: "Valid date is required in 'YYYY-MM-DD' format.",
//       });
//     }

//     const queryDate = new Date(date);
//     if (isNaN(queryDate.getTime())) {
//       return res.status(400).json({ message: "Invalid date format." });
//     }

//     // founder mode filter
//     const isFounderMode = founder === "true";
//     const doctorFilter = isFounderMode
//       ? { doctor: process.env.FOUNDER_DOCTOR_ID }
//       : {};

//     // fetch slots and appointments
//     const [doctorSlotsDocs, appointments] = await Promise.all([
//       DoctorTimeSlot.find(doctorFilter)
//         .select("doctor slots")
//         .populate("doctor", "fullname email")
//         .lean(),
//       Appointment.find({
//         date: queryDate,
//         status: { $in: ["scheduled", "completed"] },
//         ...(isFounderMode && { doctor: process.env.FOUNDER_DOCTOR_ID }),
//       })
//         .select("doctor timeSlot")
//         .lean(),
//     ]);

//     // Map booked slots
//     const bookedSlotMap = new Map();
//     appointments.forEach((app) => {
//       const key = `${app.doctor.toString()}_${app.timeSlot.startTime}-${
//         app.timeSlot.endTime
//       }`;
//       bookedSlotMap.set(key, true);
//     });

//     // Build available slots
//     const slotMap = new Map();

//     doctorSlotsDocs.forEach((doc) => {
//       if (!doc.doctor) return;

//       doc.slots.forEach((slot) => {
//         const slotKey = `${slot.startTime}-${slot.endTime}`;
//         const bookingKey = `${doc.doctor._id.toString()}_${slotKey}`;

//         // Skip booked slots only
//         if (bookedSlotMap.has(bookingKey)) return;

//         // DO NOT skip past slots, even for today

//         if (!slotMap.has(slotKey)) {
//           slotMap.set(slotKey, {
//             startTime: slot.startTime,
//             endTime: slot.endTime,
//             doctors: [],
//           });
//         }

//         slotMap.get(slotKey).doctors.push({
//           doctorId: doc.doctor._id,
//           name: doc.doctor.fullname,
//           email: doc.doctor.email,
//         });
//       });
//     });

//     const availableSlots = Array.from(slotMap.values());

//     return res.status(200).json({
//       date,
//       founder: isFounderMode,
//       availableSlots,
//       count: availableSlots.length,
//     });
//   } catch (error) {
//     console.error("Error fetching available slots:", error);
//     return res.status(500).json({
//       message: "An error occurred while fetching available slots.",
//       error:
//         process.env.NODE_ENV === "production" ? "Server error" : error.message,
//     });
//   }
// };

const razorpay = new Razorpay({
  key_id: process.env.RAZORPAY_KEY_ID,
  key_secret: process.env.RAZORPAY_KEY_SECRET,
});

const autoBookAppointment = async (req, res) => {
  try {
    const {
      date,
      startTime,
      endTime,
      bundleId,
      founder,
      continueWithSameDoctor,
      planId,
    } = req.body;
    const patientId = req.user.id;

    if (
      !date ||
      !startTime ||
      !endTime ||
      !/^\d{4}-\d{2}-\d{2}$/.test(date) ||
      !/^([01]\d|2[0-3]):([0-5]\d)$/.test(startTime) ||
      !/^([01]\d|2[0-3]):([0-5]\d)$/.test(endTime)
    ) {
      return res.status(400).json({
        message:
          "Please provide date (YYYY-MM-DD), startTime, and endTime in HH:mm format.",
      });
    }

    // Parse date in UTC
    let dateObj;
    if (typeof date === "string" && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
      const [year, month, day] = date.split("-");
      dateObj = new Date(
        Date.UTC(Number(year), Number(month) - 1, Number(day))
      );
    } else {
      dateObj = new Date(date);
    }
    if (isNaN(dateObj.getTime())) {
      return res.status(400).json({ message: "Invalid date format." });
    }

    //   const bundle = await Bundle.findById(bundleId);
    // const appointments = await Appointment.find({ userId, bundleId });

    // const currentSessionCount = appointments.length;

    // const validation = validateInstallmentsBeforeBooking(bundle, currentSessionCount);
    // if (!validation.valid) {
    //   return res.status(400).json({ message: validation.message });
    // }

    let selectedDoctor;
    let isFounderSelected = founder === true;

    // Doctor selection logic
    if (isFounderSelected) {
      const founderSlot = await DoctorTimeSlot.findOne({
        doctor: process.env.FOUNDER_DOCTOR_ID,
        slots: { $elemMatch: { startTime, endTime } },
      }).populate("doctor", "fullname email");

      if (!founderSlot) {
        return res
          .status(404)
          .json({ message: "Founder is not available at the selected time." });
      }

      const alreadyBooked = await Appointment.findOne({
        date: dateObj,
        "timeSlot.startTime": startTime,
        "timeSlot.endTime": endTime,
        doctor: process.env.FOUNDER_DOCTOR_ID,
        bundleId,
        planId,
        status: { $in: ["scheduled", "completed", "pending"] }, // Added pending
      });

      if (alreadyBooked) {
        return res
          .status(409)
          .json({ message: "Founder is already booked at the selected time." });
      }

      selectedDoctor = founderSlot;
    } else {
      if (continueWithSameDoctor === true) {
        const lastAppointment = await Appointment.findOne({
          patient: patientId,
          doctor: { $ne: null },
        })
          .sort({ date: -1 })
          .populate("doctor", "fullname email");

        if (!lastAppointment) {
          return res
            .status(404)
            .json({ message: "No previous doctor found for this user." });
        }

        const doctorId = lastAppointment.doctor._id;
        const slot = await DoctorTimeSlot.findOne({
          doctor: doctorId,
          slots: { $elemMatch: { startTime, endTime } },
        }).populate("doctor", "fullname email");

        if (!slot) {
          return res.status(404).json({
            message: "Previous doctor not available at selected time.",
          });
        }

        const alreadyBooked = await Appointment.findOne({
          date: dateObj,
          "timeSlot.startTime": startTime,
          "timeSlot.endTime": endTime,
          doctor: doctorId,
          bundleId,
          planId,
          status: { $in: ["scheduled", "completed", "pending"] }, // Added pending
        });

        if (alreadyBooked) {
          return res.status(409).json({
            message: "Previous doctor is already booked at the selected time.",
          });
        }

        selectedDoctor = slot;
      } else {
        const [doctorsWithSlot, bookedAppointments] = await Promise.all([
          DoctorTimeSlot.find({
            slots: { $elemMatch: { startTime, endTime } },
          })
            .populate("doctor", "fullname email")
            .lean(),
          Appointment.find({
            date: dateObj,
            "timeSlot.startTime": startTime,
            "timeSlot.endTime": endTime,
            bundleId,
            planId,
            status: { $in: ["scheduled", "completed", "pending"] },
          }).lean(),
        ]);

        if (!doctorsWithSlot.length) {
          return res
            .status(404)
            .json({ message: "No doctors available for the given time slot." });
        }

        const bookedDoctorIds = new Set(
          bookedAppointments.map((a) => String(a.doctor))
        );
        const availableDoctors = doctorsWithSlot.filter((docSlot) => {
          console.log(
            "Checking doctor:",
            docSlot.doctor ? docSlot.doctor._id : "No doctor"
          );
          return (
            docSlot.doctor &&
            docSlot.doctor._id && // Ensure _id exists
            !bookedDoctorIds.has(String(docSlot.doctor._id))
          );
        });

        if (!availableDoctors.length) {
          return res
            .status(409)
            .json({ message: "All doctors are booked for this time slot." });
        }

        selectedDoctor =
          availableDoctors[Math.floor(Math.random() * availableDoctors.length)];
      }
    }

    // Get doctor and patient details for Meet link generation
    const [doctorDetails, patientDetails] = await Promise.all([
      User.findById(selectedDoctor.doctor._id).select("fullname email"),
      User.findById(patientId).select("fullname email"),
    ]);

    // Generate PROPER Google Meet link
    const meetLinkData = await generateMeetLinkForAppointment({
      patientName: patientDetails.fullname,
      patientEmail: patientDetails.email,
      doctorName: doctorDetails.fullname,
      doctorEmail: doctorDetails.email,
      startDateTime: new Date(`${date} ${startTime}`).toISOString(),
      endDateTime: new Date(`${date} ${endTime}`).toISOString(),
    });

    // Create pending appointment with Meet link
    const appointment = await Appointment.create({
      date: dateObj,
      timeSlot: { startTime, endTime },
      doctor: selectedDoctor.doctor._id,
      patient: patientId,
      status: "pending",
      founder: isFounderSelected,
      bundleId,
      planId,
      meetLink: meetLinkData.meetLink,
    });

    // If bundleId is provided, mark as scheduled and send notification
    if (bundleId) {
      await Appointment.findByIdAndUpdate(appointment._id, {
        status: "scheduled",
      });

      const patient = await User.findById(patientId);

      // Fix phone number formatting with proper logic
      const mobile = String(patient.mobile || "").replace(/\D/g, "");
      const countryCode = String(patient.countryCode || "").replace(/\D/g, "");

      // Format phone number properly for India
      let fullPhone;
      if (mobile.startsWith("91")) {
        fullPhone = `+${mobile}`;
      } else if (countryCode && mobile) {
        fullPhone = `+${countryCode}${mobile}`;
      } else if (mobile.length === 10) {
        // Indian mobile numbers are 10 digits, add +91
        fullPhone = `+91${mobile}`;
      } else {
        fullPhone = `+${mobile}`;
      }

      console.log("📱 Sending appointment confirmation to:", fullPhone);
      console.log("🔍 Debug - countryCode:", countryCode, "mobile:", mobile);

      // Send professional appointment confirmation with Google Meet link
      // sendAppointmentConfirmation(
      //   fullPhone,
      //   patient.email,
      //   {
      //     patientName: patient.fullname,
      //     doctorName: selectedDoctor.doctor.fullname,
      //     date: date,
      //     startTime: startTime,
      //     endTime: endTime,
      //     meetLink: meetLinkData.meetLink,
      //     meetingCode: meetLinkData.meetingCode,
      //     meetingType: meetLinkData.type
      //   },
      //   patient._id
      // ).catch((err) => console.error("Failed to send appointment confirmation:", err));
    }

    return res.status(201).json({
      message: bundleId
        ? "Appointment booked successfully."
        : "Appointment created, proceed to payment.",
      appointment: {
        id: appointment._id,
        date: appointment.date,
        timeSlot: appointment.timeSlot,
        founder: appointment.founder,
        planId,
        meetLink: meetLinkData.meetLink,
        meetingCode: meetLinkData.meetingCode,
        meetingType: meetLinkData.type,
        doctor: {
          id: selectedDoctor.doctor._id,
          name: selectedDoctor.doctor.fullname,
          email: selectedDoctor.doctor.email,
        },
      },
    });
  } catch (error) {
    console.error("Error auto booking appointment:", error);
    return res.status(500).json({
      message: "An error occurred while booking the appointment.",
      error:
        process.env.NODE_ENV === "production" ? "Server error" : error.message,
    });
  }
};

const submitFeedback = async (req, res) => {
  const patientId = req.user.id;
  const { sessionId } = req.params;
  const { rating, review } = req.body;

  if (!rating || rating < 1 || rating > 5) {
    return res
      .status(400)
      .json({ success: false, message: "Rating (1-5) is required." });
  }

  try {
    const appointment = await Appointment.findById(sessionId);
    if (!appointment) {
      return res
        .status(404)
        .json({ success: false, message: "Appointment not found" });
    }

    if (appointment.patient.toString() !== patientId) {
      return res
        .status(403)
        .json({ success: false, message: "Unauthorized feedback attempt" });
    }

    const existing = await AppointmentFeedback.findOne({
      appointment: sessionId,
    });
    if (existing) {
      return res
        .status(409)
        .json({ success: false, message: "Feedback already submitted" });
    }

    const feedback = await AppointmentFeedback.create({
      appointment: sessionId,
      patient: patientId,
      doctor: appointment.doctor,
      rating,
      review,
    });

    return res
      .status(201)
      .json({ success: true, message: "Feedback submitted", data: feedback });
  } catch (error) {
    console.error("Submit feedback error:", error);
    return res.status(500).json({ success: false, message: "Server Error" });
  }
};

//client panel apis
// const getAvailableSlotsClient = async (req, res) => {
//   try {
//     const { date } = req.query;
//     const patientId = req.user.id;
//     // Validate date format
//     if (!date || !date.match(/^\d{4}-\d{2}-\d{2}$/)) {
//       return res.status(400).json({
//         message: "Valid date is required in 'YYYY-MM-DD' format.",
//       });
//     }

//     const queryDate = new Date(date);
//     if (isNaN(queryDate.getTime())) {
//       return res.status(400).json({ message: "Invalid date format." });
//     }

//     // Validate patientId
//     if (!patientId || !mongoose.Types.ObjectId.isValid(patientId)) {
//       return res.status(400).json({ message: "Valid patient ID is required." });
//     }

//     // Check if the query date is today
//     const now = new Date();
//     const isToday = queryDate.toDateString() === now.toDateString();
//     const currentTime = isToday ? now.toTimeString().slice(0, 5) : null; // "HH:MM" format

//     // Find the doctor from patient's most recent completed session
//     const lastSession = await Appointment.findOne({
//       patient: patientId,
//       status: "completed",
//     })
//       .sort({ createdAt: -1 }) // Get most recent
//       .select("doctor")
//       .lean();

//     if (!lastSession) {
//       return res.status(404).json({
//         message: "No completed sessions found for this patient.",
//       });
//     }

//     const doctorId = lastSession.doctor;

//     // Fetch doctor's slots and appointments in parallel
//     const [doctorSlots, appointments] = await Promise.all([
//       DoctorTimeSlot.findOne({ doctor: doctorId }).select("slots").lean(),

//       Appointment.find({
//         doctor: doctorId,
//         date: queryDate,
//         status: { $in: ["scheduled", "completed"] },
//       })
//         .select("timeSlot")
//         .lean(),
//     ]);

//     if (!doctorSlots) {
//       return res.status(404).json({ message: "Doctor's schedule not found." });
//     }

//     // Create a set of booked time slots for quick lookup
//     const bookedSlots = new Set();
//     appointments.forEach((app) => {
//       bookedSlots.add(`${app.timeSlot.startTime}-${app.timeSlot.endTime}`);
//     });

//     // Filter available slots
//     const availableSlots = doctorSlots.slots
//       .filter((slot) => {
//         const slotKey = `${slot.startTime}-${slot.endTime}`;

//         // Skip if slot is booked
//         if (bookedSlots.has(slotKey)) return false;

//         // Skip past slots if the date is today
//         if (isToday && slot.startTime < currentTime) return false;

//         return true;
//       })
//       .map((slot) => ({
//         startTime: slot.startTime,
//         endTime: slot.endTime,
//       }));

//     return res.status(200).json({
//       date,
//       doctorId,
//       availableSlots,
//       count: availableSlots.length,
//     });
//   } catch (error) {
//     console.error("Error fetching available slots:", error);
//     return res.status(500).json({
//       message: "An error occurred while fetching available slots.",
//       error:
//         process.env.NODE_ENV === "production" ? "Server error" : error.message,
//     });
//   }
// };

const getAvailableSlotsTherapist = async (req, res) => {
  try {
    const { date } = req.query;
    const therapistId = req.user.id;

    if (!date || !date.match(/^\d{4}-\d{2}-\d{2}$/)) {
      return res
        .status(400)
        .json({ message: "Valid date is required in 'YYYY-MM-DD' format." });
    }
    if (!therapistId || !mongoose.Types.ObjectId.isValid(therapistId)) {
      return res
        .status(400)
        .json({ message: "Valid therapist ID is required." });
    }

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

    const now = new Date();
    const isToday = queryDate.toDateString() === now.toDateString();
    const currentTime = isToday ? now.toTimeString().slice(0, 5) : null;

    // Get the therapist's slots and their booked appointments
    const [timeSlotDoc, appointments] = await Promise.all([
      DoctorTimeSlot.findOne({ doctor: therapistId }).select("slots").lean(),
      Appointment.find({
        doctor: therapistId,
        date: queryDate,
        status: { $in: ["scheduled", "completed"] },
      })
        .select("timeSlot")
        .lean(),
    ]);

    if (!timeSlotDoc) {
      return res
        .status(404)
        .json({ message: "Therapist's timetable not found." });
    }

    const bookedSlots = new Set();
    appointments.forEach((app) => {
      bookedSlots.add(`${app.timeSlot.startTime}-${app.timeSlot.endTime}`);
    });

    const availableSlots = timeSlotDoc.slots
      .filter((slot) => {
        const slotKey = `${slot.startTime}-${slot.endTime}`;
        if (bookedSlots.has(slotKey)) return false;
        if (isToday && slot.startTime < currentTime) return false;
        return true;
      })
      .map((slot) => ({
        startTime: slot.startTime,
        endTime: slot.endTime,
      }));

    res.status(200).json({
      date,
      therapistId,
      availableSlots,
      count: availableSlots.length,
    });
  } catch (error) {
    console.error("Error fetching available slots:", error);
    res.status(500).json({
      message: "An error occurred while fetching available slots.",
      error:
        process.env.NODE_ENV === "production" ? "Server error" : error.message,
    });
  }
};
const rescheduleAppointment = async (req, res) => {
  try {
    const therapistId = req.user.id;
    const { id } = req.params; // appointment id
    const { date, startTime, endTime } = req.body;

    if (!mongoose.Types.ObjectId.isValid(id)) {
      return res.status(400).json({ message: "Invalid appointment ID." });
    }
    if (!date || !date.match(/^\d{4}-\d{2}-\d{2}$/)) {
      return res
        .status(400)
        .json({ message: "Valid date is required in 'YYYY-MM-DD' format." });
    }
    if (!startTime || !endTime) {
      return res
        .status(400)
        .json({ message: "Both startTime and endTime are required." });
    }

    // Find appointment and check ownership
    const appointment = await Appointment.findById(id);
    if (!appointment) {
      return res.status(404).json({ message: "Appointment not found." });
    }
    if (appointment.doctor.toString() !== therapistId) {
      return res
        .status(403)
        .json({ message: "Unauthorized: Not your appointment." });
    }
    if (["completed", "cancelled"].includes(appointment.status)) {
      return res.status(400).json({
        message: "Cannot reschedule a completed or cancelled appointment.",
      });
    }

    // Check if the time slot is available
    const queryDate = new Date(date);

    // Is this slot in therapist's allowed slots?
    const timeSlotDoc = await DoctorTimeSlot.findOne({
      doctor: therapistId,
    }).lean();
    if (!timeSlotDoc) {
      return res
        .status(404)
        .json({ message: "Therapist's timetable not found." });
    }

    const allowedSlot = timeSlotDoc.slots.find(
      (slot) => slot.startTime === startTime && slot.endTime === endTime
    );
    if (!allowedSlot) {
      return res
        .status(400)
        .json({ message: "This slot is not available in your timetable." });
    }

    // Is this slot already booked for this date?
    const conflict = await Appointment.findOne({
      doctor: therapistId,
      date: queryDate,
      "timeSlot.startTime": startTime,
      "timeSlot.endTime": endTime,
      status: { $in: ["scheduled", "completed"] },
      _id: { $ne: id }, // ignore the current appointment
    });

    if (conflict) {
      return res.status(409).json({ message: "This slot is already booked." });
    }

    // All good! Reschedule.
    appointment.date = queryDate;
    appointment.timeSlot = { startTime, endTime };
    await appointment.save();

    res.status(200).json({
      message: "Appointment rescheduled successfully.",
      appointment,
    });
  } catch (error) {
    console.error("Error rescheduling appointment:", error);
    res.status(500).json({
      message: "An error occurred while rescheduling appointment.",
      error:
        process.env.NODE_ENV === "production" ? "Server error" : error.message,
    });
  }
};

const getAvailableSlotsClient = async (req, res) => {
  try {
    const { date, reschedule } = req.query;
    const patientId = req.user.id;

    // Validate date format
    if (!date || !date.match(/^\d{4}-\d{2}-\d{2}$/)) {
      return res.status(400).json({
        message: "Valid date is required in 'YYYY-MM-DD' format.",
      });
    }

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

    // Validate patientId
    if (!patientId || !mongoose.Types.ObjectId.isValid(patientId)) {
      return res.status(400).json({ message: "Valid patient ID is required." });
    }

    // Check if the query date is today
    const now = new Date();
    const isToday = queryDate.toDateString() === now.toDateString();
    const currentTime = isToday ? now.toTimeString().slice(0, 5) : null; // "HH:MM" format

    // Find the doctor from the patient's most recent session
    let lastSession;

    if (reschedule) {
      lastSession = await Appointment.findOne({
        patient: patientId,
        status: "scheduled",
      })
        .sort({ createdAt: -1 }) // Get the most recent
        .select("doctor")
        .lean();
    } else {
      lastSession = await Appointment.findOne({
        patient: patientId,
        status: "completed",
      })
        .sort({ createdAt: -1 }) // Get the most recent
        .select("doctor")
        .lean();
    }

    if (!lastSession) {
      return res.status(404).json({
        message: reschedule
          ? "No scheduled sessions found for the user"
          : "No Plan added for the user.",
      });
    }

    const doctorId = lastSession.doctor;

    // Fetch doctor's slots and appointments in parallel
    const [doctorSlots, appointments] = await Promise.all([
      DoctorTimeSlot.findOne({ doctor: doctorId }).select("slots").lean(),
      Appointment.find({
        doctor: doctorId,
        date: queryDate,
        status: { $in: ["scheduled", "completed"] },
      })
        .select("timeSlot")
        .lean(),
    ]);

    if (!doctorSlots) {
      return res.status(404).json({ message: "Doctor's schedule not found." });
    }

    // Create a set of booked time slots for quick lookup
    const bookedSlots = new Set();
    appointments.forEach((app) => {
      bookedSlots.add(`${app.timeSlot.startTime}-${app.timeSlot.endTime}`);
    });

    // Filter available slots
    const availableSlots = doctorSlots.slots
      .filter((slot) => {
        const slotKey = `${slot.startTime}-${slot.endTime}`;

        // Skip if slot is booked
        if (bookedSlots.has(slotKey)) return false;

        // Skip past slots if the date is today
        if (isToday && slot.startTime < currentTime) return false;

        return true;
      })
      .map((slot) => ({
        startTime: slot.startTime,
        endTime: slot.endTime,
      }));

    return res.status(200).json({
      date,
      doctorId,
      availableSlots,
      count: availableSlots.length,
    });
  } catch (error) {
    console.error("Error fetching available slots:", error);
    return res.status(500).json({
      message: "An error occurred while fetching available slots.",
      error:
        process.env.NODE_ENV === "production" ? "Server error" : error.message,
    });
  }
};

const getUserScheduledAppointments = async (req, res) => {
  try {
    const patientId = req.user.id; // Get the user ID from the request (assumed to be set by authentication middleware)

    // Fetch scheduled appointments for the user
    const appointments = await Appointment.find({
      patient: patientId,
      status: "scheduled", // Only fetch scheduled appointments
    })
      .populate("doctor", "name") // Assuming you want to get doctor's name; adjust as necessary
      .lean();

    if (appointments.length === 0) {
      return res
        .status(404)
        .json({ message: "No scheduled appointments found." });
    }

    return res.status(200).json({
      success: true,
      message: "Scheduled appointments retrieved successfully.",
      appointments,
    });
  } catch (error) {
    console.error("Error fetching scheduled appointments:", error);
    return res.status(500).json({
      message: "An error occurred while fetching scheduled appointments.",
      error:
        process.env.NODE_ENV === "production" ? "Server error" : error.message,
    });
  }
};

const bundleIndividualBooking = async (req, res) => {};

const rescheduleAppointmentUser = async (req, res) => {
  const { id } = req.params; // Appointment ID from URL
  const { newDate, newStartTime, newEndTime } = req.body; // New date and time from request body

  try {
    // Validate the new date and time format here if necessary

    // Find the appointment and update it
    const appointment = await Appointment.findById(id);
    if (!appointment) {
      return res.status(404).json({ message: "Appointment not found" });
    }

    // Update the appointment fields
    appointment.date = newDate;
    appointment.timeSlot.startTime = newStartTime;
    appointment.timeSlot.endTime = newEndTime;
    appointment.status = "scheduled"; // Change status as needed

    // Save the updated appointment
    await appointment.save();

    return res
      .status(200)
      .json({ message: "Appointment rescheduled successfully", appointment });
  } catch (error) {
    console.error(error);
    return res.status(500).json({
      message: "An error occurred while rescheduling the appointment",
    });
  }
};
module.exports = {
  addOrUpdateTimeSlots,
  getThirtyMinSlotsWithBreaks,
  getAvailableSlots,
  autoBookAppointment,
  submitFeedback,
  getAvailableSlotsClient,

  rescheduleAppointment,
  getAvailableSlotsTherapist,
  rescheduleAppointmentUser,
  getUserScheduledAppointments,
};
