import { Request, Response, NextFunction } from "express";
import { catchAsyncError } from "../../middlewares/catchAsyncError";
import { AuthRequest } from "../../middlewares/auth";
import ErrorHandler from "../../middlewares/error";
import database from "../../config/db";
import {
  productReviewService,
  ReviewFilters,
  ReviewCreateData,
} from "./product.review.service";

export const productReviewController = {
  // Create new review
  createReview: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      const data: ReviewCreateData = {
        ...req.body,
        creator_id: userId,
      };

      // Check if user can review this product
      const canReview = await productReviewService.canUserReviewProduct(
        data.product_id,
        userId,
      );

      if (!canReview.can_review) {
        return next(new ErrorHandler(canReview.reason, 400));
      }

      try {
        const review = await productReviewService.createReview(data);

        // Emit socket event for real-time updates
        if (req.app.get("io")) {
          const io = req.app.get("io");
          io.to(`product:${data.product_id}`).emit("review:created", {
            review,
            product_id: data.product_id,
          });
        }

        res.status(201).json({
          success: true,
          message: "Review submitted successfully",
          data: review,
        });
      } catch (error: any) {
        return next(new ErrorHandler(error.message, 400));
      }
    },
  ),

  // Get review by ID
  getReviewById: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { id } = req.params;

      const review = await productReviewService.getReviewById(id);

      if (!review) {
        return next(new ErrorHandler("Review not found", 404));
      }

      res.status(200).json({
        success: true,
        data: review,
      });
    },
  ),

  // Get user's review for a product
  getUserProductReview: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { productId } = req.params;
      const userId = req.user?.id;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      const review = await productReviewService.getUserProductReview(
        productId,
        userId,
      );

      res.status(200).json({
        success: true,
        data: review || null,
      });
    },
  ),

  // Get all reviews
  getAllReviews: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const {
        page = 1,
        limit = 20,
        product_id,
        creator_id,
        status = "approved",
        min_rating,
        max_rating,
        is_verified_purchase,
        would_recommend,
        sort_by = "created_at",
        order = "desc",
        helpful,
      } = req.query;

      const filters: ReviewFilters = {
        page: parseInt(page as string),
        limit: parseInt(limit as string),
        product_id: product_id as string,
        creator_id: creator_id as string,
        status: status as string,
        min_rating: min_rating ? parseFloat(min_rating as string) : undefined,
        max_rating: max_rating ? parseFloat(max_rating as string) : undefined,
        is_verified_purchase: is_verified_purchase
          ? is_verified_purchase === "true"
          : undefined,
        would_recommend: would_recommend
          ? would_recommend === "true"
          : undefined,
        sort_by: sort_by as string,
        order: order as "asc" | "desc",
        helpful: helpful === "true",
      };

      const result = await productReviewService.getAllReviews(filters);

      res.status(200).json({
        success: true,
        ...result,
      });
    },
  ),

  // Get product review statistics
  getProductReviewStats: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { productId } = req.params;

      const stats = await productReviewService.getProductReviewStats(productId);

      res.status(200).json({
        success: true,
        data: stats,
      });
    },
  ),

  // Get rating distribution
  getProductRatingDistribution: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { productId } = req.params;

      const distribution =
        await productReviewService.getProductRatingDistribution(productId);

      res.status(200).json({
        success: true,
        data: distribution,
      });
    },
  ),

  // Update review
  updateReview: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const userId = req.user?.id;
      const data = req.body;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      // Validate rating if provided
      if (data.rating !== undefined && (data.rating < 0 || data.rating > 5)) {
        return next(new ErrorHandler("Rating must be between 0 and 5", 400));
      }

      try {
        const updatedReview = await productReviewService.updateReview(
          id,
          data,
          userId,
        );

        res.status(200).json({
          success: true,
          message: "Review updated successfully",
          data: updatedReview,
        });
      } catch (error: any) {
        return next(
          new ErrorHandler(
            error.message,
            error.message.includes("own") ? 403 : 400,
          ),
        );
      }
    },
  ),

  // Delete review
  deleteReview: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const userId = req.user?.id;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      try {
        const deletedReview = await productReviewService.deleteReview(
          id,
          userId,
        );

        res.status(200).json({
          success: true,
          message: "Review deleted successfully",
          data: deletedReview,
        });
      } catch (error: any) {
        return next(
          new ErrorHandler(
            error.message,
            error.message.includes("own") ? 403 : 400,
          ),
        );
      }
    },
  ),

  // Mark review as helpful
  markReviewHelpful: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const userId = req.user?.id;
      const { helpful = true } = req.body;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      try {
        const result = await productReviewService.markHelpful(
          id,
          userId,
          helpful,
        );

        res.status(200).json({
          success: true,
          message: `Review marked as ${helpful ? "helpful" : "not helpful"}`,
          data: result,
        });
      } catch (error: any) {
        return next(new ErrorHandler(error.message, 400));
      }
    },
  ),

  // Moderate review (approve/reject)
  moderateReview: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const { status, reason } = req.body;
      const userId = req.user?.id;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      // Check if user has moderator/admin permissions
      const isModerator = req.user?.roles?.some((role: any) =>
        ["admin", "super_admin", "moderator"].includes(role.name),
      );

      if (!isModerator) {
        return next(
          new ErrorHandler("Only moderators can moderate reviews", 403),
        );
      }

      if (!["approved", "rejected"].includes(status)) {
        return next(
          new ErrorHandler("Invalid status. Use 'approved' or 'rejected'", 400),
        );
      }

      try {
        const moderatedReview = await productReviewService.moderateReview(
          id,
          status,
          userId,
          reason,
        );

        // Notify review creator about moderation
        if (req.app.get("io")) {
          const io = req.app.get("io");
          io.to(`user:${moderatedReview.creator_id}`).emit("review:moderated", {
            review_id: id,
            status,
            reason,
            moderated_by: userId,
          });
        }

        res.status(200).json({
          success: true,
          message: `Review ${status} successfully`,
          data: moderatedReview,
        });
      } catch (error: any) {
        return next(new ErrorHandler(error.message, 400));
      }
    },
  ),

  // Get user's reviews
  getUserReviews: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;
      const {
        page = 1,
        limit = 20,
        status = "approved",
        product_id,
      } = req.query;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      const filters = {
        page: parseInt(page as string),
        limit: parseInt(limit as string),
        status: status as string,
        product_id: product_id as string,
      };

      const result = await productReviewService.getUserReviews(userId, filters);

      res.status(200).json({
        success: true,
        ...result,
      });
    },
  ),

  // Get recent reviews
  getRecentReviews: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const limit = parseInt(req.query.limit as string) || 10;

      const reviews = await productReviewService.getRecentReviews(limit);

      res.status(200).json({
        success: true,
        data: reviews,
      });
    },
  ),

  // Get top helpful reviews for a product
  getTopHelpfulReviews: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { productId } = req.params;
      const limit = parseInt(req.query.limit as string) || 5;

      const reviews = await productReviewService.getTopHelpfulReviews(
        productId,
        limit,
      );

      res.status(200).json({
        success: true,
        data: reviews,
      });
    },
  ),

  // Get verified purchase reviews
  getVerifiedPurchaseReviews: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { productId } = req.params;
      const limit = parseInt(req.query.limit as string) || 10;

      const reviews = await productReviewService.getVerifiedPurchaseReviews(
        productId,
        limit,
      );

      res.status(200).json({
        success: true,
        data: reviews,
      });
    },
  ),

  // Get reviews by rating
  getReviewsByRating: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { productId, rating } = req.params;
      const { page = 1, limit = 20, status = "approved" } = req.query;

      const ratingNum = parseInt(rating);
      if (ratingNum < 1 || ratingNum > 5) {
        return next(new ErrorHandler("Rating must be between 1 and 5", 400));
      }

      const filters = {
        page: parseInt(page as string),
        limit: parseInt(limit as string),
        status: status as string,
      };

      const result = await productReviewService.getReviewsByRating(
        productId,
        ratingNum,
        filters,
      );

      res.status(200).json({
        success: true,
        ...result,
      });
    },
  ),

  // Check if user can review product
  canUserReview: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { productId } = req.params;
      const userId = req.user?.id;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      const result = await productReviewService.canUserReviewProduct(
        productId,
        userId,
      );

      res.status(200).json({
        success: true,
        data: result,
      });
    },
  ),

  // Get review summary for dashboard (admin)
  getReviewSummary: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;
      const days = parseInt(req.query.days as string) || 30;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      // Check if user is admin
      const isAdmin = req.user?.roles?.some((role: any) =>
        ["admin", "super_admin"].includes(role.name),
      );

      if (!isAdmin) {
        return next(new ErrorHandler("Admin access required", 403));
      }

      const summary = await productReviewService.getReviewSummary(days);

      res.status(200).json({
        success: true,
        data: summary,
      });
    },
  ),

  // Bulk update reviews (admin)
  bulkUpdateReviews: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;
      const { review_ids, status, is_verified_purchase } = req.body;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      // Check if user is admin/moderator
      const isModerator = req.user?.roles?.some((role: any) =>
        ["admin", "super_admin", "moderator"].includes(role.name),
      );

      if (!isModerator) {
        return next(new ErrorHandler("Moderator access required", 403));
      }

      if (!Array.isArray(review_ids) || review_ids.length === 0) {
        return next(new ErrorHandler("Review IDs array is required", 400));
      }

      if (status && !["approved", "rejected", "pending"].includes(status)) {
        return next(new ErrorHandler("Invalid status", 400));
      }

      const updateData: any = {};
      if (status) updateData.status = status;
      if (is_verified_purchase !== undefined) {
        updateData.is_verified_purchase = is_verified_purchase;
      }

      try {
        const updatedReviews = await productReviewService.bulkUpdateReviews(
          review_ids,
          updateData,
        );

        res.status(200).json({
          success: true,
          message: `${updatedReviews.length} reviews updated successfully`,
          data: updatedReviews,
        });
      } catch (error: any) {
        return next(new ErrorHandler(error.message, 400));
      }
    },
  ),

  // Get pending reviews for moderation
  getPendingReviews: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;
      const { page = 1, limit = 20 } = req.query;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      // Check if user is moderator/admin
      const isModerator = req.user?.roles?.some((role: any) =>
        ["admin", "super_admin", "moderator"].includes(role.name),
      );

      if (!isModerator) {
        return next(new ErrorHandler("Moderator access required", 403));
      }

      const filters: ReviewFilters = {
        page: parseInt(page as string),
        limit: parseInt(limit as string),
        status: "pending",
        sort_by: "created_at",
        order: "asc",
      };

      const result = await productReviewService.getAllReviews(filters);

      res.status(200).json({
        success: true,
        ...result,
      });
    },
  ),

  // Get review analytics
  getReviewAnalytics: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;

      if (!userId) {
        return next(new ErrorHandler("Authentication required", 401));
      }

      // Check if user is admin
      const isAdmin = req.user?.roles?.some((role: any) =>
        ["admin", "super_admin"].includes(role.name),
      );

      if (!isAdmin) {
        return next(new ErrorHandler("Admin access required", 403));
      }

      const query = `
      SELECT 
        COUNT(*) as total_reviews,
        COUNT(CASE WHEN status = 'approved' THEN 1 END) as approved,
        COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending,
        COUNT(CASE WHEN status = 'rejected' THEN 1 END) as rejected,
        AVG(rating)::DECIMAL(3,2) as avg_rating,
        COUNT(CASE WHEN is_verified_purchase = true THEN 1 END) as verified,
        COUNT(CASE WHEN would_recommend = true THEN 1 END) as would_recommend,
        DATE_TRUNC('month', created_at) as month,
        COUNT(*) as monthly_count
      FROM products_reviews
      WHERE created_at >= CURRENT_DATE - INTERVAL '6 months'
      GROUP BY DATE_TRUNC('month', created_at)
      ORDER BY month DESC;
    `;

      const result = await database.query(query);

      res.status(200).json({
        success: true,
        data: result.rows,
      });
    },
  ),
};
