const Plan = require("../../models/Plan");
const Appointment = require("../../models/Appointment");
const User = require("../../models/userModel");
const mongoose = require("mongoose");
const Payment = require("../../models/payment");
const Razorpay = require("razorpay");
const crypto = require("crypto");
const { generateMeetLinkForAppointment } = require("../../utils/googleMeet");
const {
  sendAppointmentConfirmation,
} = require("../../utils/mendingMindTemplates");
const razorpay = new Razorpay({
  key_id: process.env.RAZORPAY_KEY_ID,
  key_secret: process.env.RAZORPAY_KEY_SECRET,
});
const getInstallments = async (req, res) => {
  try {
    const planId = req.params.id;
    const plan = await Plan.findById(planId);

    if (!plan) {
      return res.status(404).json({ error: "Plan not found." });
    }

    // Calculate only the sessions the user has NOT completed individually
    const totalPayableSessions =
      plan.sessionCount - plan.completedSessionsIndividual;
    const totalAmount = totalPayableSessions * plan.amount;

    // Divide payable sessions into installments (no adjustment for completed sessions)
    const firstInstallmentSessions = Math.floor(totalPayableSessions / 2);
    const secondInstallmentSessions =
      totalPayableSessions - firstInstallmentSessions;

    // Calculate installment amounts
    const firstInstallmentAmount = firstInstallmentSessions * plan.amount;
    const secondInstallmentAmount = secondInstallmentSessions * plan.amount;

    const installments = [
      {
        number: 1,
        amount: firstInstallmentAmount,
        isPaid: plan.installmentsPaid >= 1,
        unlocksSessions: firstInstallmentSessions,
      },
      {
        number: 2,
        amount: secondInstallmentAmount,
        isPaid: plan.installmentsPaid >= 2,
        unlocksSessions: secondInstallmentSessions,
      },
    ];

    const remainingSessions = plan.sessionCount - plan.completedSessions;

    res.status(200).json({
      success: true,
      totalAmount,
      totalSessions: plan.sessionCount,
      completedSessions: plan.completedSessions,
      completedSessionsIndividual: plan.completedSessionsIndividual,
      remainingSessions,
      installments,
      unlockedSessions: plan.unlockedSessions,
      installmentsPaid: plan.installmentsPaid,
      status: plan.status,
    });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
};

const payInstallment = async (req, res) => {
  try {
    const planId = req.params.id;
    const { installmentNumber } = req.body;

    // Validate installment number (must be 1 or 2)
    if (![1, 2].includes(installmentNumber)) {
      return res
        .status(400)
        .json({ error: "Invalid installment number. Must be 1 or 2." });
    }

    // Fetch the plan
    const plan = await Plan.findById(planId);
    if (!plan) {
      return res.status(404).json({ error: "Plan not found." });
    }

    // Check installment sequence (must be paid in order)
    if (plan.installmentsPaid + 1 !== installmentNumber) {
      return res.status(400).json({
        error: "You can only pay the next unpaid installment in order.",
        installmentsPaid: plan.installmentsPaid,
      });
    }

    // Calculate payable sessions
    const totalPayableSessions =
      plan.sessionCount - plan.completedSessionsIndividual;

    const firstInstallmentSessions = Math.floor(totalPayableSessions / 2);
    const secondInstallmentSessions =
      totalPayableSessions - firstInstallmentSessions;

    let sessionsToUnlock = 0;
    if (installmentNumber === 1) {
      sessionsToUnlock = firstInstallmentSessions;
    } else if (installmentNumber === 2) {
      sessionsToUnlock = secondInstallmentSessions;
    }

    // Add unlocked sessions for both installments
    plan.unlockedSessions = sessionsToUnlock;

    // Update the number of installments paid
    plan.installmentsPaid += 1;

    // If this is the first installment, set status to 'active'
    if (installmentNumber === 1 && plan.status === "pending") {
      plan.status = "active";
    }

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

    res.status(200).json({
      success: true,
      message: `Installment ${installmentNumber} payment successful. ${sessionsToUnlock} sessions unlocked.`,
      plan: {
        _id: plan._id,
        installmentsPaid: plan.installmentsPaid,
        unlockedSessions: plan.unlockedSessions,
        status: plan.status,
      },
    });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
};

const bookBundelAppointment = async (req, res) => {
  try {
    const { date, startTime, endTime } = req.body;
    const userId = req.user.id;

    if (!date || !startTime || !endTime) {
      return res.status(400).json({
        message: "date, startTime, and endTime are required.",
      });
    }

    // Check if the user already has a scheduled appointment
    const existingScheduled = await Appointment.findOne({
      patient: userId,
      status: "scheduled",
    });

    if (existingScheduled) {
      return res.status(409).json({
        message:
          "You already have a scheduled appointment. Please complete or cancel your existing appointment before booking a new one.",
      });
    }

    // Find the last completed session for this user (patient)
    const lastSession = await Appointment.findOne({
      patient: userId,
      status: "completed",
    })
      .sort({ createdAt: -1 })
      .select("doctor")
      .lean();

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

    const therapistId = lastSession.doctor;

    // Check if any plan exists for this user and doctor
    const anyPlan = await Plan.findOne({
      userId: new mongoose.Types.ObjectId(userId),
      doctorId: new mongoose.Types.ObjectId(therapistId),
    });

    if (!anyPlan) {
      return res.status(404).json({
        message:
          "No plan found for this user. Please purchase a plan before booking.",
      });
    }

    // Now, check for an active plan
    const activePlan = await Plan.findOne({
      userId: new mongoose.Types.ObjectId(userId),
      doctorId: new mongoose.Types.ObjectId(therapistId),
      status: "active",
    });

    if (activePlan) {
      if (activePlan.unlockedSessions > 0) {
        // Get doctor and patient details for Meet link generation
        const [doctorDetails, patientDetails] = await Promise.all([
          User.findById(therapistId).select("fullname email"),
          User.findById(userId).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(),
        });

        // Proceed to book appointment
        const timeSlot = {
          startTime,
          endTime,
        };

        const newAppointment = new Appointment({
          date,
          timeSlot,
          doctor: therapistId,
          patient: userId,
          status: "scheduled",
          plan: activePlan._id,
          meetLink: meetLinkData.meetLink,
        });

        await newAppointment.save();

        // Send appointment confirmation notification
        const patient = await User.findById(userId);
        const therapist = await User.findById(therapistId);

        if (patient && therapist) {
          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 bundle appointment confirmation to:",
            fullPhone
          );
          console.log(
            "🔍 Debug - countryCode:",
            countryCode,
            "mobile:",
            mobile
          );

          // sendAppointmentConfirmation(
          //   fullPhone,
          //   patient.email,
          //   {
          //     patientName: patient.fullname,
          //     doctorName: therapist.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 bundle appointment confirmation:", err));
        }

        return res.status(201).json({
          message: "Appointment booked successfully",
          appointment: {
            ...newAppointment.toObject(),
            meetLink: meetLinkData.meetLink,
          },
          requiresPayment: false,
        });
      } else {
        return res.status(200).json({
          requiresPayment: true,
          message:
            "Your active plan does not have any unlocked sessions left. Please proceed to payment to book this appointment.",
        });
      }
    } else {
      // No active plan, check for pending plan
      const pendingPlan = await Plan.findOne({
        userId: new mongoose.Types.ObjectId(userId),
        doctorId: new mongoose.Types.ObjectId(therapistId),
        status: "pending",
      });

      if (pendingPlan) {
        return res.status(200).json({
          message:
            "You have a pending plan. Please complete payment to activate your plan and book appointments.",
          requiresPayment: true,
        });
      } else {
        return res.status(404).json({
          message:
            "No active or pending plan found. Please purchase a plan before booking.",
        });
      }
    }
  } catch (error) {
    console.error("Error booking appointment:", error);
    return res.status(500).json({
      message: "An error occurred while booking the appointment.",
      error: error.message,
    });
  }
};

const getPlanAmount = async (req, res) => {
  try {
    // If using authentication middleware, userId should be in req.user.id
    // Otherwise, use req.params.userId or req.query.userId as needed
    const userId = req.user?.id || req.params.userId || req.query.userId;

    if (!userId) {
      return res.status(400).json({
        message: "User ID is required.",
      });
    }

    // Find the latest plan for the user
    const latestPlan = await Plan.findOne({ userId: userId }).sort({
      createdAt: -1,
    }); // Sort descending by creation date

    if (!latestPlan) {
      return res.status(404).json({
        message: "No plan found for this user.",
      });
    }

    return res.status(200).json({
      success: true,
      amount: latestPlan.amount,
    });
  } catch (error) {
    console.error("Error fetching latest plan amount:", error);
    return res.status(500).json({
      message: "An error occurred while fetching the plan amount.",
      error: error.message,
    });
  }
};

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

    // Input validation
    if (!date || !startTime || !endTime) {
      return res
        .status(400)
        .json({ message: "date, startTime, and endTime are required." });
    }

    // Get logged-in user ID (patient)
    const patientId = req.user.id;

    // Find last appointment for patient to get doctor
    const lastAppointment = await Appointment.findOne({
      patient: patientId,
      status: "completed",
    }).sort({ createdAt: -1 });

    if (!lastAppointment || !lastAppointment.doctor) {
      return res.status(404).json({
        message: "No previous appointment found to determine therapist.",
      });
    }

    const doctorId = lastAppointment.doctor;

    // Get doctor and patient details for Meet link generation
    const [doctorDetails, patientDetails] = await Promise.all([
      User.findById(doctorId).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 new appointment with status set to "scheduled"
    const newAppointment = new Appointment({
      date,
      timeSlot: {
        startTime,
        endTime,
      },
      doctor: doctorId,
      patient: patientId,
      status: "scheduled", // Explicitly set status here
      meetLink: meetLinkData.meetLink,
    });

    await newAppointment.save();

    // Send appointment confirmation notification
    const patient = await User.findById(patientId);
    const doctor = await User.findById(doctorId);

    if (patient && doctor) {
      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 direct appointment confirmation to:", fullPhone);
      console.log("🔍 Debug - countryCode:", countryCode, "mobile:", mobile);

      // sendAppointmentConfirmation(
      //   fullPhone,
      //   patient.email,
      //   {
      //     patientName: patient.fullname,
      //     doctorName: 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 direct appointment confirmation:", err)
      // );
    }

    return res.status(201).json({
      message: "Appointment booked and scheduled successfully.",
      appointment: {
        ...newAppointment.toObject(),
        meetLink: meetLinkData.meetLink,
      },
    });
  } catch (error) {
    console.error(error);
    return res
      .status(500)
      .json({ message: "Server error while booking appointment." });
  }
};

//installment payment apis
// POST /api/installments/create/:id
const createInstallmentPayment = async (req, res) => {
  try {
    const planId = req.params.id;
    const userId = req.user.id;
    const plan = await Plan.findOne({ _id: planId, userId: userId });

    if (!plan) {
      return res.status(404).json({ error: "Plan not found." });
    }

    // Determine next unpaid installment
    const nextInstallmentNumber = plan.installmentsPaid + 1;
    if (![1, 2].includes(nextInstallmentNumber)) {
      return res
        .status(400)
        .json({ error: "All installments are already paid." });
    }

    // Calculate sessions and amount for this installment
    const totalPayableSessions =
      plan.sessionCount - plan.completedSessionsIndividual;
    const firstInstallmentSessions = Math.floor(totalPayableSessions / 2);
    const secondInstallmentSessions =
      totalPayableSessions - firstInstallmentSessions;

    let sessions = 0;
    if (nextInstallmentNumber === 1) sessions = firstInstallmentSessions;
    else if (nextInstallmentNumber === 2) sessions = secondInstallmentSessions;

    const amount = sessions * plan.amount * 100; // in paise

    // Create Razorpay order
    const order = await razorpay.orders.create({
      amount,
      currency: "INR",
      receipt: `p${planId.slice(0, 10)}i${nextInstallmentNumber}${Date.now()
        .toString()
        .slice(-6)}`,
      payment_capture: 1,
    });

    await Payment.create({
      orderId: order.id,
      plan: planId,
      patient: userId,
      amount: order.amount,
      currency: order.currency,
      status: "pending",
    });

    return res.json({
      success: true,
      orderId: order.id,
      amount: order.amount,
      currency: order.currency,
      key: process.env.RAZORPAY_KEY_ID,
      installmentNumber: nextInstallmentNumber,
      planId,
    });
  } catch (err) {
    console.error("Error creating installment payment:", err);
    res.status(500).json({ error: err.message });
  }
};

// POST /api/installments/verify
const verifyInstallmentPayment = async (req, res) => {
  try {
    const {
      planId,
      installmentNumber,
      razorpay_payment_id,
      razorpay_order_id,
      razorpay_signature,
    } = req.body;

    // Verify signature
    const expectedSignature = crypto
      .createHmac("sha256", process.env.RAZORPAY_KEY_SECRET)
      .update(razorpay_order_id + "|" + razorpay_payment_id)
      .digest("hex");

    if (expectedSignature !== razorpay_signature) {
      // Update payment status as failed
      await Payment.findOneAndUpdate(
        { orderId: razorpay_order_id },
        { status: "failed", razorpaySignature: razorpay_signature }
      );
      return res.status(400).json({ error: "Invalid payment signature." });
    }

    // Update payment as completed
    await Payment.findOneAndUpdate(
      { orderId: razorpay_order_id },
      {
        paymentId: razorpay_payment_id,
        status: "completed",
        razorpaySignature: razorpay_signature,
      }
    );

    // Signature is valid, unlock sessions
    req.params.id = planId;
    req.body.installmentNumber = installmentNumber;

    // Call business logic
    await payInstallment(req, res);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
};

const initiatePayment = async (req, res) => {
  try {
    const { amount, currency = "INR" } = req.body;
    const patient = req.user.id;

    if (!amount || !patient) {
      return res.status(400).json({ message: "Amount and patient required" });
    }

    // Create Razorpay order
    const order = await razorpay.orders.create({
      amount: amount * 100, // in paise
      currency,
      receipt: `receipt_${Date.now()}`,
      payment_capture: 1,
    });

    // Save payment record (pending)
    const payment = new Payment({
      patient,
      orderId: order.id,
      amount,
      currency,
      status: "pending",
    });
    await payment.save();

    return res.json({
      success: true,
      orderId: order.id,
      amount: order.amount,
      currency: order.currency,
      key: process.env.RAZORPAY_KEY_ID,
    });
  } catch (err) {
    console.error("Initiate payment error:", err);
    res.status(500).json({ message: "Failed to initiate payment" });
  }
};

const verifyPayment = async (req, res) => {
  try {
    const { orderId, paymentId, razorpaySignature, date, startTime, endTime } =
      req.body;

    // Validate input
    if (!orderId || !paymentId || !razorpaySignature) {
      return res.status(400).json({ message: "Missing payment fields" });
    }
    if (!date || !startTime || !endTime) {
      return res
        .status(400)
        .json({ message: "date, startTime, and endTime are required." });
    }

    // Signature validation
    const generatedSignature = crypto
      .createHmac("sha256", process.env.RAZORPAY_KEY_SECRET)
      .update(orderId + "|" + paymentId)
      .digest("hex");

    if (generatedSignature !== razorpaySignature) {
      await Payment.findOneAndUpdate(
        { orderId },
        { status: "failed", razorpaySignature }
      );
      return res.status(400).json({ message: "Payment signature mismatch" });
    }

    // Mark payment as completed
    const payment = await Payment.findOneAndUpdate(
      { orderId },
      {
        status: "completed",
        paymentId,
        razorpaySignature,
        updatedAt: Date.now(),
      },
      { new: true }
    );

    if (!payment) {
      return res.status(404).json({ message: "Payment record not found" });
    }

    // Get patient id from payment
    const patientId = payment.patient;

    // Find last completed appointment for patient to get doctor
    const lastAppointment = await Appointment.findOne({
      patient: patientId,
      status: "completed",
    }).sort({ createdAt: -1 });

    if (!lastAppointment || !lastAppointment.doctor) {
      return res.status(404).json({
        message: "No previous appointment found to determine therapist.",
      });
    }
    const doctorId = lastAppointment.doctor;

    // Get doctor and patient details for Meet link generation
    const [doctorDetails, patientDetails] = await Promise.all([
      User.findById(doctorId).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 new appointment
    const newAppointment = new Appointment({
      date,
      timeSlot: {
        startTime,
        endTime,
      },
      doctor: doctorId,
      patient: patientId,
      status: "scheduled",
      meetLink: meetLinkData.meetLink,
    });
    await newAppointment.save();

    // Send appointment confirmation notification
    const patient = await User.findById(patientId);
    const doctor = await User.findById(doctorId);

    if (patient && doctor) {
      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 payment verification appointment confirmation to:",
        fullPhone
      );
      console.log("🔍 Debug - countryCode:", countryCode, "mobile:", mobile);

      // sendAppointmentConfirmation(
      //   fullPhone,
      //   patient.email,
      //   {
      //     patientName: patient.fullname,
      //     doctorName: 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 payment verification appointment confirmation:",
      //     err
      //   )
      // );
    }

    // Link appointment to payment
    payment.appointment = newAppointment._id;
    await payment.save();

    return res.json({
      success: true,
      message: "Payment verified and appointment booked successfully.",
      appointment: {
        ...newAppointment.toObject(),
        meetLink: meetLinkData.meetLink,
      },
      payment,
    });
  } catch (error) {
    console.error(error);
    return res
      .status(500)
      .json({ message: "Server error during payment verification." });
  }
};
module.exports = {
  getInstallments,
  payInstallment,
  bookBundelAppointment,
  getPlanAmount,
  bookAppointment,
  createInstallmentPayment,
  verifyInstallmentPayment,
  initiatePayment,
  verifyPayment,
};
