const { QueryTypes, Op } = require('sequelize');
const { HostReviews, Users, sequelize, Bookings } = require('../../models');
const { paginate } = require('../../util/pagination');
const { errorHandler, formatTimestamp } = require('../../util');

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: { [Op.in]: ['Done', 'Cancelled'] },
      },
      include: [{ model: Users, as: 'host' }],
    });

    if (!booking) {
      return errorHandler('No valid booking found.', 404);
    }

    if (!booking.host) {
      return errorHandler('Host not found', 404);
    }

    const existingReview = await HostReviews.findOne({
      where: { booking_id: bookingId, user_id: userId, host_id: booking.host.id },
    });

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

    const review = await HostReviews.create({
      content: req.body.content,
      rating: req.body.rating,
      host_id: booking.host.id,
      user_id: userId,
      booking_id: bookingId,
    });

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

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

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

    if (!review) {
      return errorHandler('Review not found', 404);
    }

    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 HostReviews.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 { hostId } = req.params;
    const { page, limit } = req.query;

    if (!hostId) {
      return res.status(400).json({
        success: false,
        message: 'Please provide a listing id',
      });
    }

    const hostReviews = await sequelize.query(
      `
			SELECT
				hr.id,
				hr.rating,
				hr.content,
				hr.createdAt,
				u.id AS userId,
				u.firstName,
				u.lastName,
				u.image
			FROM host_reviews hr
			LEFT JOIN users u ON hr.user_id = u.id
			WHERE hr.host_id = ?
			`,
      {
        type: QueryTypes.SELECT,
        replacements: [hostId],
      },
    );

    const cleanHostReviews = hostReviews.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: cleanHostReviews,
      });
    }

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

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