import Rating from "../DB/Model/rating.modal.js";
import User from "../DB/Model/user.model.js";
import { createRatingSchema, updateRatingSchema } from "../Utils/Validator/ratingValidation.js";
import push_notification from "../Config/push_notification.js";
import Booking from "../DB/Model/booking.modal.js";

/**
 * 🔹 Calculate average rating for a user (receiver)
 */
export const calculateUserRating = async (userId) => {
  try {
    const ratingList = await Rating.find({ receiverId: userId }).select("rating");
    if (ratingList.length === 0) {
      await User.findByIdAndUpdate(userId, { averageRating: 0 });
      return;
    }

    let total = 0;
    ratingList.forEach((r) => (total += parseFloat(r.rating)));
    const avg = (total / ratingList.length).toFixed(1);

    await User.findByIdAndUpdate(userId, {
      averageRating: parseFloat(avg),
    });
  } catch (err) {
    console.error("Error calculating user rating:", err.message);
  }
};

/**
 * 🔹 Create a new rating
 */
export const createRating = async (req, res) => {
  try {
    const { error } = createRatingSchema.validate(req.body);
    if (error) {
      return res.status(400).json({ status: false, message: error.details[0].message });
    }

    const userId = req.user._id;
    const { bookingId, rating, review } = req.body;

    const booking = await Booking.findById(bookingId).populate("serviceId");
    if (!booking) {
      return res.status(404).json({ status: false, message: "Booking not found." });
    }

    // ✅ Determine receiver
    let receiverId;
    if (userId.toString() === booking.userId.toString()) {
      receiverId = booking.accepted_by; // gainer → provider
    } else if (userId.toString() === booking.accepted_by.toString()) {
      receiverId = booking.userId; // provider → gainer
    } else {
      return res.status(400).json({ status: false, message: "Invalid booking relationship." });
    }

    // ✅ Prevent duplicate
    const existing = await Rating.findOne({ userId, bookingId });
    if (existing) {
      return res.status(400).json({
        status: false,
        message: "You have already rated this booking.",
      });
    }

    // 🟢 Create rating
    const newRating = await Rating.create({
      userId,
      receiverId,
      serviceId: booking.serviceId._id,
      bookingId,
      rating,
      review,
    });

    // 🟢 Update receiver's average rating
    await calculateUserRating(receiverId);

    // 🟢 Send notification
    try {
      const ratingUser = await User.findById(userId).select("full_name");
      const title = "⭐ New Rating Received";
      const body = `${ratingUser?.full_name || "A user"} rated you ${rating}⭐`;
      const link = `/bookings/${bookingId}`;

      await push_notification("new_rating", title, body, link, receiverId);
    } catch (notifyErr) {
      console.error("⚠️ Failed to send notification:", notifyErr.message);
    }

    return res.status(201).json({
      status: true,
      message: "Rating submitted successfully.",
      data: newRating,
    });
  } catch (err) {
    res.status(500).json({ status: false, message: err.message });
  }
};

/**
 * 🔹 Get ratings (given, received, or all)
 */
export const getAllRatings = async (req, res) => {
  try {
    const { type } = req.query; // "given" | "received" | "all"
    const userId = req.user._id;

    let givenRatings = [];
    let receivedRatings = [];

    // 🟢 Common populate config
    const populateConfig = [
      { path: "userId", select: "full_name image" }, // Who gave rating
      { path: "receiverId", select: "full_name image" }, // Who received rating
      {
        path: "bookingId",
        select: "serviceId accepted_by userId",
        populate: {
          path: "serviceId",
          select: "service_title price created_by",
          populate: {
            path: "created_by",
            select: "full_name image",
          },
        },
      },
    ];

    if (type === "given") {
      givenRatings = await Rating.find({ userId }).populate(populateConfig);
    } else if (type === "received") {
      receivedRatings = await Rating.find({ receiverId: userId }).populate(populateConfig);
    } else {
      [givenRatings, receivedRatings] = await Promise.all([
        Rating.find({ userId }).populate(populateConfig),
        Rating.find({ receiverId: userId }).populate(populateConfig),
      ]);
    }

    return res.status(200).json({
      status: true,
      message: "Ratings fetched successfully.",
      myGivenRatings: givenRatings,
      myReceivedRatings: receivedRatings,
    });
  } catch (err) {
    console.error("❌ Error fetching ratings:", err);
    return res.status(500).json({ status: false, message: err.message });
  }
};

/**
 * 🔹 Update rating
 */
export const updateRating = async (req, res) => {
  try {
    const { error } = updateRatingSchema.validate(req.body);
    if (error) {
      return res.status(400).json({ status: false, message: error.details[0].message });
    }

    const { id } = req.params;
    const { rating, review } = req.body;

    const existingRating = await Rating.findById(id);

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

    if (existingRating.userId.toString() !== req.user._id.toString()) {
      return res.status(403).json({ status: false, message: "Unauthorized to update this rating." });
    }

    const updated = await Rating.findByIdAndUpdate(
      id,
      { rating, review },
      { new: true }
    );

    // ✅ Recalculate for receiver
    await calculateUserRating(existingRating.receiverId);

    res.status(200).json({
      status: true,
      message: "Rating updated successfully.",
      data: updated,
    });
  } catch (err) {
    res.status(500).json({ status: false, message: err.message });
  }
};

/**
 * 🔹 Delete rating
 */
export const deleteRating = async (req, res) => {
  try {
    const { id } = req.params;

    const rating = await Rating.findById(id);
    if (!rating) {
      return res.status(404).json({ status: false, message: "Rating not found." });
    }

    if (rating.userId.toString() !== req.user._id.toString()) {
      return res.status(403).json({ status: false, message: "Unauthorized to delete this rating." });
    }

    await Rating.findByIdAndDelete(id);

    // ✅ Recalculate for receiver
    await calculateUserRating(rating.receiverId);

    res.status(200).json({
      status: true,
      message: "Rating deleted successfully.",
    });
  } catch (err) {
    res.status(500).json({ status: false, message: err.message });
  }
};
