const { QueryTypes } = require('sequelize');
const { ListingReviews, sequelize, Bookings } = require('../../models');
const { paginate } = require('../../util/pagination');
const { formatTimestamp } = require('../../util');
const { formatCase } = require('../../util/formatter');

exports.createReview = async (req, res, next) => {
  try {
    const { userId } = req;
    const { bookingId } = req.params;

    const booking = await Bookings.findOne({
      where: {
        id: bookingId,
        customer_id: userId,
        status: 'Done',
      },
      include: [
        {
          model: ListingReviews,
          as: 'listingReview',
        },
      ],
    });

    if (!booking) {
      return res.status(400).json({
        success: false,
        message: 'Valid booking not found for this listing',
      });
    }

    if (booking.listingReview) {
      return res.status(400).json({
        success: false,
        message: 'You have already reviewed this booking',
        review: formatCase(booking.listingReview),
      });
    }

    await ListingReviews.create({
      content: req.body.content,
      rating: req.body.rating,
      listing_id: booking.listing_id,
      booking_id: booking.id,
      user_id: userId,
    });

    return res.status(201).json({
      success: true,
      message: 'Review created successfully',
    });
  } catch (error) {
    next(error);
  }
};

exports.updateReview = async (req, res, next) => {
  try {
    const { userId } = req;
    const { reviewId } = req.params;

    const review = await ListingReviews.findOne({
      where: { id: reviewId },
    });

    if (!review) {
      return res.status(404).json({
        success: false,
        message: 'Review not found',
      });
    }

    if (review.user_id !== userId) {
      return res.status(403).json({
        success: false,
        message: 'You are not authorized to update this review',
      });
    }

    for (const key of ['rating', 'content']) {
      if (key in req.body) {
        review[key] = req.body[key];
      }
    }

    await review.save();

    return res.status(200).json({
      success: true,
      message: 'Review updated successfully',
    });
  } catch (error) {
    next(error);
  }
};

exports.deleteReview = async (req, res, next) => {
  try {
    const { userId } = req;
    const { reviewId } = req.params;

    const review = await ListingReviews.findOne({
      where: { id: reviewId },
    });

    if (!review) {
      return res.status(404).json({
        success: false,
        message: 'Review not found',
      });
    }

    if (review.user_id !== userId) {
      return res.status(403).json({
        success: false,
        message: 'You are not authorized to delete this review',
      });
    }

    await review.destroy();

    return res.status(200).json({
      success: true,
      message: 'Review deleted successfully',
    });
  } catch (error) {
    next(error);
  }
};

exports.getReviews = async (req, res, next) => {
  try {
    const { listingId } = req.params;
    const { page, limit } = req.query;

    if (!listingId) {
      return res.status(400).json({
        success: false,
        message: 'Please provide a listing id',
      });
    }
    const listingReviews = await sequelize.query(
      `
			SELECT
				lr.id,
				lr.rating,
				lr.content,
				lr.createdAt,
				u.id AS userId,
				u.firstName,
				u.lastName,
				u.image,
				u.id as user_id
			FROM listing_reviews lr
			LEFT JOIN users u ON lr.user_id = u.id
			WHERE lr.listing_id = ?
			`,
      {
        type: QueryTypes.SELECT,
        replacements: [listingId],
      },
    );

    const cleanlistingReviews = listingReviews.map((review) => {
      return {
        id: review.id,
        rating: review.rating,
        content: review.content,
        createdAt: formatTimestamp(review.createdAt),
        user: {
          fullname: `${review.firstName || ''} ${review.lastName || ''}`.trim() || 'Deleted User',
          image: review.image
            ? `${process.env.BASE_URL}/public/user-uploads/${review.image}`
            : null,
          id: review.userId,
        },
      };
    });

    if (!page || !limit) {
      return res.status(200).json({
        success: true,
        data: cleanlistingReviews,
      });
    }

    const paginated = paginate(cleanlistingReviews, parseInt(page), parseInt(limit));

    return res.status(200).json({
      success: true,
      ...paginated,
    });
  } catch (error) {
    next(error);
  }
};
