import { Request, Response, NextFunction } from "express";
import {
  productCommentService,
  CommentFilters,
  CommentCreateData,
} from "./product.comment.service";
import database from "../../config/db";
import { AuthRequest } from "../../middlewares/auth";
import ErrorHandler from "../../middlewares/error";
import { catchAsyncError } from "../../middlewares/catchAsyncError";

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

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

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

      // Extract mentioned users from comment text
      if (data.comment) {
        const mentionRegex = /@(\w+)/g;
        const mentions = [...data.comment.matchAll(mentionRegex)].map(
          (match) => match[1],
        );

        // You would typically look up user IDs from usernames here
        // For now, we'll leave mentioned_users as provided
        if (mentions.length > 0 && !data.mentioned_users) {
          data.mentioned_users = []; // Placeholder for actual user IDs
        }
      }

      try {
        const comment = await productCommentService.createComment(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("comment:created", {
            comment,
            product_id: data.product_id,
          });
        }

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

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

      const comment = await productCommentService.getCommentById(id);

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

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

  // Get all comments for a product
  getProductComments: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { productId } = req.params;
      const {
        page = 1,
        limit = 20,
        parent_id,
        status = "active",
        sort_by = "created_at",
        order = "desc",
        include_replies = false,
      } = req.query;

      const filters: CommentFilters = {
        page: parseInt(page as string),
        limit: parseInt(limit as string),
        product_id: productId,
        parent_id: parent_id === "null" ? null : (parent_id as string),
        status: status as string,
        sort_by: sort_by as string,
        order: order as "asc" | "desc",
        include_replies: include_replies === "true",
      };

      const result = await productCommentService.getProductComments(
        productId,
        filters,
      );

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

  // Get comment thread/replies
  getCommentThread: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const depth = parseInt(req.query.depth as string) || 3;

      const thread = await productCommentService.getCommentThread(id, depth);

      if (thread.length === 0) {
        return next(new ErrorHandler("Comment not found", 404));
      }

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

  // Update comment
  updateComment: 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));
      }

      try {
        const updatedComment = await productCommentService.updateComment(
          id,
          data,
          userId,
        );

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

  // Delete comment
  deleteComment: 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 deletedComment = await productCommentService.deleteComment(
          id,
          userId,
        );

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

  // Upvote a comment
  upvoteComment: 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 result = await productCommentService.upvoteComment(id, userId);

        res.status(200).json({
          success: true,
          message: "Comment upvoted successfully",
          data: { upvotes: result.upvotes },
        });
      } catch (error: any) {
        return next(new ErrorHandler(error.message, 400));
      }
    },
  ),

  // Downvote a comment
  downvoteComment: 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 result = await productCommentService.downvoteComment(id, userId);

        res.status(200).json({
          success: true,
          message: "Comment downvoted successfully",
          data: { downvotes: result.downvotes },
        });
      } catch (error: any) {
        return next(new ErrorHandler(error.message, 400));
      }
    },
  ),

  // Pin/unpin a comment
  pinComment: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const { pinned = true } = req.body;
      const userId = req.user?.id;

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

      // Check if user is product owner or admin
      const comment = await productCommentService.getCommentById(id);
      if (!comment) {
        return next(new ErrorHandler("Comment not found", 404));
      }

      // Get product to check ownership
      const productResult = await database.query(
        `SELECT creator_id FROM products WHERE id = $1`,
        [comment.product_id],
      );

      const isProductOwner = productResult.rows[0]?.creator_id === userId;
      const isAdmin = req.user?.roles?.some(
        (role: any) => role.name === "admin" || role.name === "super_admin",
      );

      if (!isProductOwner && !isAdmin) {
        return next(
          new ErrorHandler("Only product owner or admin can pin comments", 403),
        );
      }

      try {
        const updatedComment = await productCommentService.pinComment(
          id,
          pinned,
        );

        res.status(200).json({
          success: true,
          message: `Comment ${pinned ? "pinned" : "unpinned"} successfully`,
          data: updatedComment,
        });
      } catch (error: any) {
        return next(new ErrorHandler(error.message, 400));
      }
    },
  ),

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

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

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

      const result = await productCommentService.getUserComments(
        userId,
        filters,
      );

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

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

      const stats =
        await productCommentService.getProductCommentStats(productId);

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

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

      const comments = await productCommentService.getRecentComments(limit);

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

  // Report a comment
  reportComment: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const userId = req.user?.id;
      const { reason } = req.body;

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

      if (!reason || reason.trim().length < 5) {
        return next(
          new ErrorHandler(
            "Please provide a valid reason (min 5 characters)",
            400,
          ),
        );
      }

      try {
        const reportedComment = await productCommentService.reportComment(
          id,
          userId,
          reason,
        );

        // Notify admins (optional)
        if (req.app.get("io")) {
          const io = req.app.get("io");
          io.to("admin:notifications").emit("comment:reported", {
            comment_id: id,
            reporter_id: userId,
            reason,
          });
        }

        res.status(200).json({
          success: true,
          message: "Comment reported successfully",
          data: reportedComment,
        });
      } catch (error: any) {
        return next(new ErrorHandler(error.message, 400));
      }
    },
  ),

  // Get comments with mentions
  getCommentsWithMentions: 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));
      }

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

      const result = await productCommentService.getCommentsWithMentions(
        userId,
        filters,
      );

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

  // Get comment by product and user
  getUserProductComment: 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 query = `
      SELECT 
        c.*,
        creator.username as creator_username,
        creator.display_name as creator_display_name,
        creator.avatar as creator_avatar,
        product.name as product_name
      FROM products_comments c
      LEFT JOIN accounts creator ON c.creator_id = creator.id
      LEFT JOIN products product ON c.product_id = product.id
      WHERE c.product_id = $1 AND c.creator_id = $2 AND c.status = 'active'
      ORDER BY c.created_at DESC
      LIMIT 1;
    `;

      const result = await database.query(query, [productId, userId]);

      if (result.rows.length === 0) {
        return next(new ErrorHandler("No comment found", 404));
      }

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

  // Bulk delete comments (admin only)
  bulkDeleteComments: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { comment_ids } = req.body;

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

      if (comment_ids.length > 100) {
        return next(
          new ErrorHandler("Cannot delete more than 100 comments at once", 400),
        );
      }

      const results = [];
      for (const commentId of comment_ids) {
        try {
          const deleted = await productCommentService.deleteComment(
            commentId,
            req.user?.id,
          );
          results.push({ id: commentId, success: true, data: deleted });
        } catch (error: any) {
          results.push({ id: commentId, success: false, error: error.message });
        }
      }

      res.status(200).json({
        success: true,
        message: "Bulk delete completed",
        data: results,
      });
    },
  ),

  // Restore deleted comment
  restoreComment: 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));
      }

      const query = `
      UPDATE products_comments
      SET status = 'active', updated_at = CURRENT_TIMESTAMP
      WHERE id = $1 AND (creator_id = $2 OR EXISTS(
        SELECT 1 FROM accounts WHERE id = $2 AND (
          SELECT COUNT(*) FROM role_assignments ra
          INNER JOIN roles r ON ra.role_id = r.id
          WHERE ra.account_id = $2 
            AND (r.name = 'admin' OR r.name = 'super_admin')
        ) > 0
      ))
      RETURNING *;
    `;

      const result = await database.query(query, [id, userId]);

      if (result.rows.length === 0) {
        return next(
          new ErrorHandler(
            "Comment not found or you don't have permission",
            404,
          ),
        );
      }

      res.status(200).json({
        success: true,
        message: "Comment restored successfully",
        data: result.rows[0],
      });
    },
  ),
};
