const mongoose = require("mongoose");
const Slot = require("../models/slotModel");
const Appointment = require("../models/appointmentModel");
const Leave = require("../models/leaveModel");
const { errorResponse } = require("../utils/errorResponseHandler");
const { logUserAction } = require("../utils/userActionLogger");
const Patient = require("../models/patientModel");



// const bookAppointment = async (req, res) => {
//     try {
//         const { slotId, startTime, endTime, patientId } = req.body;
//         const userId = req.user._id;
//         const orgId = req.user.orgId;

//         //  Get slot document
//         const slotDoc = await Slot.findById(slotId);
//         if (!slotDoc) {
//             return res.status(404).json({ success: false, message: "Slot not found" });
//         }

//         const { doctor, date } = slotDoc;

//         //  Check doctor leave (range logic)
//         const selectedDate = new Date(date);
//         selectedDate.setHours(0, 0, 0, 0);
//         const nextDay = new Date(selectedDate);
//         nextDay.setDate(nextDay.getDate() + 1);

//         const leave = await Leave.findOne({
//             employee: doctor,
//             orgId,
//             status: "Approved",
//             startDate: { $lt: nextDay },
//             endDate: { $gte: selectedDate },
//             isDeleted: false,
//         });

//         if (leave) {
//             return res.status(400).json({
//                 success: false,
//                 message: "Doctor is on leave for this date",
//             });
//         }

//         //  Atomically book slot
//         const updated = await Slot.findOneAndUpdate(
//             {
//                 _id: slotId,
//                 "slots.startTime": startTime,
//                 "slots.isBooked": false,
//             },
//             {
//                 $set: {
//                     "slots.$.isBooked": true,
//                     "slots.$.bookedBy": userId,
//                 },
//             },
//             { new: true }
//         );

//         if (!updated) {
//             return res.status(409).json({
//                 success: false,
//                 message: "Slot already booked by another user",
//             });
//         }

//         //  Create appointment
//         await Appointment.create({
//             doctor,
//             patient: patientId,
//             date,
//             startTime,
//             endTime,
//             slotRef: slotId,
//             orgId,
//             bookedBy: userId,
//             status: "Booked",
//         });

//         return res.status(200).json({
//             success: true,
//             message: "Appointment booked successfully",
//         });
//     } catch (err) {
//         console.error(err);
//         return res.status(500).json({
//             success: false,
//             message: "Failed to book appointment",
//         });
//     }
// };


const bookAppointment = async (req, res) => {
  try {
    const {
      slotId,
      date,
      startTime,
      endTime,
      patient,
    } = req.body;

    const userId = req.user._id;
    const orgId = req.user.orgId;

    if (!slotId || !startTime || !endTime || !patient?.phone) {
      return res.status(400).json({
        success: false,
        message: "Missing required fields",
      });
    }

    /* ================= GET SLOT DOCUMENT ================= */

    const slotDoc = await Slot.findById(slotId);
    if (!slotDoc) {
      return res.status(404).json({
        success: false,
        message: "Slot not found",
      });
    }

    const { doctor } = slotDoc;

    /* ================= CHECK DOCTOR LEAVE ================= */

    const selectedDate = new Date(date);
    selectedDate.setHours(0, 0, 0, 0);

    const nextDay = new Date(selectedDate);
    nextDay.setDate(nextDay.getDate() + 1);

    const leave = await Leave.findOne({
      employee: doctor,
      orgId,
      status: "Approved",
      startDate: { $lt: nextDay },
      endDate: { $gte: selectedDate },
      isDeleted: false,
    });

    if (leave) {
      return res.status(400).json({
        success: false,
        message: "Doctor is on leave for this date",
      });
    }

    /* ================= FIND OR CREATE PATIENT ================= */

    let existingPatient = await Patient.findOne({
      phone: patient.phone,
      orgId,
      isDeleted: false,
    });

    if (!existingPatient) {
        
      const patientCount = await Patient.countDocuments({ orgId });
      existingPatient = await Patient.create({
        patientId: `PAT-${String(patientCount + 1).padStart(5, "0")}`,
        name: patient.name,
        phone: patient.phone,
        type: patient.type,
        address: patient.address,
        orgId,
        createdBy: userId,
      });
    }

    /* ================= ATOMIC SLOT BOOKING ================= */

    const updated = await Slot.findOneAndUpdate(
      {
        _id: slotId,
        doctor,
        orgId,
        "slots.startTime": startTime,
        "slots.isBooked": false,
      },
      {
        $set: {
          "slots.$.isBooked": true,
          "slots.$.bookedBy": userId,
        },
      },
      { new: true }
    );

    if (!updated) {
      return res.status(409).json({
        success: false,
        message: "Slot already booked by another user",
      });
    }

    /* ================= CREATE APPOINTMENT ================= */

    const appointment = await Appointment.create({
      doctor,
      patient: existingPatient._id,
      date,
      startTime,
      endTime,
      slotRef: slotId,
      orgId,
      bookedBy: userId,
      status: "Booked",
    });

    return res.status(201).json({
      success: true,
      message: "Appointment booked successfully",
      appointment,
    });

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



const getAllAppointments = async (req, res) => {
    try {
        const orgId = req.user.orgId;
        const { page = 1, limit = 10, date, status } = req.query;

        const query = {
            orgId,
            isDeleted: false,
        };

        if (date) query.date = date;
        if (status && status !== "all") query.status = status;

        const skip = (page - 1) * limit;

        const appointments = await Appointment.find(query)
            .populate("patient", "patientId name  phone")
            .populate("doctor", "firstName lastName")
            .sort({ createdAt: -1 })
            .skip(skip)
            .limit(Number(limit));

        const total = await Appointment.countDocuments(query);

        const data = appointments.map((a) => ({
            id: a._id,
            patientName: `${a.patient.name}`,
            patientPhone: a.patient.phone,
            doctorName: `Dr. ${a.doctor.firstName} ${a.doctor.lastName}`,
            date: a.date,
            remarks: a.remarks,
            slotTime: `${a.startTime} - ${a.endTime}`,
            status: a.status,
        }));

        //     await logUserAction(req, "VIEW_APPOINTMENTS", "Viewed appointments list");

        return res.status(200).json({
            success: true,
            page: Number(page),
            limit: Number(limit),
            total,
            data,
        });
    } catch (err) {
        console.error(err);
        return errorResponse(res, "Failed to fetch appointments", 500);
    }
};



const updateAppointment = async (req, res) => {
    try {
        const { id } = req.params;
        const { slotId, startTime, endTime, status } = req.body;

        const appointment = await Appointment.findById(id);
        if (!appointment) {
            return errorResponse(res, "Appointment not found", 404);
        }

        /* ---------- SLOT CHANGE (only if provided) ---------- */
        if (slotId && startTime && endTime) {
            // Free old slot
            await Slot.updateOne(
                {
                    _id: appointment.slotRef,
                    "slots.startTime": appointment.startTime,
                },
                {
                    $set: {
                        "slots.$.isBooked": false,
                        "slots.$.bookedBy": null,
                    },
                }
            );

            // Book new slot
            const updatedSlot = await Slot.findOneAndUpdate(
                {
                    _id: slotId,
                    "slots.startTime": startTime,
                    "slots.isBooked": false,
                },
                {
                    $set: {
                        "slots.$.isBooked": true,
                        "slots.$.bookedBy": req.user._id,
                    },
                },
                { new: true }
            );

            if (!updatedSlot) {
                return errorResponse(res, "Selected slot already booked", 409);
            }

            appointment.slotRef = slotId;
            appointment.startTime = startTime;
            appointment.endTime = endTime;
            appointment.date = updatedSlot.date;
            appointment.doctor = updatedSlot.doctor;
        }

        /* ---------- STATUS CHANGE (always allowed) ---------- */
        if (status) {
            appointment.status = status;
        }

        await appointment.save();
        // await logUserAction(
        //     req,
        //     "UPDATE_APPOINTMENT",
        //     `Updated appointment ${appointment._id}`
        // );

        return res.status(200).json({
            success: true,
            message: "Appointment updated successfully",
        });
    } catch (err) {
        console.error(err);
        return errorResponse(res, "Failed to update appointment", 500);
    }
};

const markAsVisited = async (req, res) => {
    try {
        const { id } = req.params;

        const appointment = await Appointment.findOne({
            _id: id,
            isDeleted: false,
        });

        if (!appointment) {
            return errorResponse(res, "Appointment not found", 404);
        }

        if (appointment.status !== "Booked") {
            return errorResponse(
                res,
                `Cannot mark as visited. Current status is ${appointment.status}`,
                400
            );
        }

        appointment.status = "Waiting";
        await appointment.save();

        // await logUserAction(
        //     req,
        //     "MARK_VISITED",
        //     `Appointment ${id} marked as Waiting`
        // );

        return res.status(200).json({
            success: true,
            message: "Patient marked as visited (Waiting)",
        });
    } catch (err) {
        console.error(err);
        return errorResponse(res, "Failed to update status", 500);
    }
};

const getSingleAppointment = async (req, res) => {
    try {
        const { id } = req.params;

        const a = await Appointment.findById(id)
            .populate("patient", "name phone")
            .populate("doctor", "firstName lastName");

        if (!a) {
            return errorResponse(res, "Appointment not found", 404);
        }

        return res.status(200).json({
            success: true,
            data: {
                patientId: a.patient._id,
                patientName: a.patient.name,
                doctorName: `Dr. ${a.doctor.firstName} ${a.doctor.lastName}`,
                doctorId: a.doctor._id,
                date: a.date,
                slotTime: `${a.startTime} - ${a.endTime}`,
                status: a.status,
            },
        });
    } catch (err) {
        return errorResponse(res, "Failed to load appointment", 500);
    }
};


// PUT /appointments/cancel/:id
const cancelAppointment = async (req, res) => {
    try {
        const { remarks } = req.body;

        const appointment = await Appointment.findByIdAndUpdate(
            req.params.id,
            {
                status: "Cancelled",
                remarks,
                cancelledAt: new Date(),
                cancelledBy: req.user.id
            },
            { new: true }
        );

        res.json({
            success: true,
            message: "Appointment cancelled successfully",
            data: appointment
        });

    } catch (err) {
        res.status(500).json({
            message: "Cancel failed"
        });
    }
};


module.exports = {
    bookAppointment,
    getAllAppointments,
    updateAppointment,
    cancelAppointment,
    markAsVisited,
    getSingleAppointment,
};