import { Request, Response, NextFunction } from "express";
import { catchAsyncError } from "../../middlewares/catchAsyncError";
import ErrorHandler from "../../middlewares/error";
import {
  productSuggestedFeatureService,
  SuggestedFeatureCreateData,
  SuggestedFeatureFilters,
} from "./product.suggested.feature.service";
import { AuthRequest } from "../../middlewares/auth";
import database from "../../config/db";

export const productSuggestedFeatureController = {
  // Create new feature suggestion
  createFeatureSuggestion: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;

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

      const data: SuggestedFeatureCreateData = {
        ...req.body,
        suggestor_id: userId,
        ip_address: req.ip,
        user_agent: req.headers["user-agent"],
      };

      // Check if product exists and is active
      if (data.product_id) {
        const productCheck = await database.query(
          `SELECT id, status FROM products WHERE id = $1`,
          [data.product_id],
        );

        if (productCheck.rows.length === 0) {
          return next(new ErrorHandler("Product not found", 404));
        }

        if (productCheck.rows[0].status !== "active") {
          return next(new ErrorHandler("Product is not active", 400));
        }
      }

      try {
        const suggestion =
          await productSuggestedFeatureService.createFeatureSuggestion(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("feature:suggested", {
            suggestion,
            product_id: data.product_id,
          });
        }

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

  // Get feature suggestion by ID
  getFeatureSuggestionById: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const incrementViews = req.query.views !== "false";

      const suggestion =
        await productSuggestedFeatureService.getFeatureSuggestionById(
          id,
          incrementViews,
        );

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

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

  // Get all feature suggestions
  getAllFeatureSuggestions: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const {
        page = 1,
        limit = 20,
        product_id,
        suggestor_id,
        assigned_to,
        status,
        tags,
        search,
        sort_by = "trending_score",
        order = "desc",
        min_upvotes,
        include_my_votes,
      } = req.query;

      const userId = (req as AuthRequest).user?.id;

      // Parse tags if provided
      let tagsArray: string[] = [];
      if (tags) {
        tagsArray = typeof tags === "string" ? tags.split(",") : [];
      }

      const filters: SuggestedFeatureFilters = {
        page: parseInt(page as string),
        limit: parseInt(limit as string),
        product_id: product_id as string,
        suggestor_id: suggestor_id as string,
        assigned_to: assigned_to as string,
        status: status as string,
        tags: tagsArray,
        search: search as string,
        sort_by: sort_by as string,
        order: order as "asc" | "desc",
        min_upvotes: min_upvotes ? parseInt(min_upvotes as string) : undefined,
        include_my_votes: include_my_votes === "true",
        user_id: userId,
      };

      const result =
        await productSuggestedFeatureService.getAllFeatureSuggestions(filters);

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

  // Get feature suggestions by product
  getProductFeatureSuggestions: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { productId } = req.params;
      const {
        page = 1,
        limit = 20,
        status,
        tags,
        search,
        sort_by = "trending_score",
        order = "desc",
        min_upvotes,
      } = req.query;

      const userId = (req as AuthRequest).user?.id;

      let tagsArray: string[] = [];
      if (tags) {
        tagsArray = typeof tags === "string" ? tags.split(",") : [];
      }

      const filters: SuggestedFeatureFilters = {
        page: parseInt(page as string),
        limit: parseInt(limit as string),
        product_id: productId,
        status: status as string,
        tags: tagsArray,
        search: search as string,
        sort_by: sort_by as string,
        order: order as "asc" | "desc",
        min_upvotes: min_upvotes ? parseInt(min_upvotes as string) : undefined,
        user_id: userId,
      };

      const result =
        await productSuggestedFeatureService.getProductFeatureSuggestions(
          productId,
          filters,
        );

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

  // Update feature suggestion
  updateFeatureSuggestion: 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 updatedSuggestion =
          await productSuggestedFeatureService.updateFeatureSuggestion(
            id,
            data,
            userId,
          );

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

  // Delete feature suggestion
  deleteFeatureSuggestion: 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 deletedSuggestion =
          await productSuggestedFeatureService.deleteFeatureSuggestion(
            id,
            userId,
          );

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

  // Vote on feature suggestion
  voteOnFeatureSuggestion: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const userId = req.user?.id;
      const { vote_type } = req.body;

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

      if (!vote_type || !["upvote", "downvote"].includes(vote_type)) {
        return next(
          new ErrorHandler(
            "Invalid vote type. Use 'upvote' or 'downvote'",
            400,
          ),
        );
      }

      try {
        const result =
          await productSuggestedFeatureService.voteOnFeatureSuggestion(
            id,
            userId,
            vote_type as "upvote" | "downvote",
          );

        // Get updated suggestion
        const updatedSuggestion =
          await productSuggestedFeatureService.getFeatureSuggestionById(
            id,
            false,
          );

        // Emit socket event
        if (req.app.get("io")) {
          const io = req.app.get("io");
          io.to(`suggestion:${id}`).emit("feature:voted", {
            suggestion_id: id,
            vote_type,
            user_id: userId,
            upvotes: updatedSuggestion?.upvotes,
            downvotes: updatedSuggestion?.downvotes,
          });
        }

        res.status(200).json({
          success: true,
          message: result.message,
          data: {
            action: result.action,
            suggestion: updatedSuggestion,
          },
        });
      } catch (error: any) {
        return next(new ErrorHandler(error.message, 400));
      }
    },
  ),

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

      const stats =
        await productSuggestedFeatureService.getSuggestionStats(productId);

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

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

      const topSuggestions =
        await productSuggestedFeatureService.getTopSuggestions(
          productId,
          limit,
        );

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

  // Get suggestions by status
  getSuggestionsByStatus: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { productId, status } = req.params;

      const suggestions =
        await productSuggestedFeatureService.getSuggestionsByStatus(
          productId,
          status,
        );

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

  // Search feature suggestions
  searchFeatureSuggestions: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { q } = req.query;
      const { product_id, status, limit = 20 } = req.query;

      if (!q || q.toString().trim().length < 2) {
        return next(
          new ErrorHandler("Search query must be at least 2 characters", 400),
        );
      }

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

      const results =
        await productSuggestedFeatureService.searchFeatureSuggestions(
          q.toString(),
          filters,
        );

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

  // Get user's suggestions
  getUserSuggestions: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;
      const { page = 1, limit = 20, product_id, status } = 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 productSuggestedFeatureService.getUserSuggestions(
        userId,
        filters,
      );

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

  // Get suggestions user has voted on
  getUserVotedSuggestions: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;

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

      const votedSuggestions =
        await productSuggestedFeatureService.getUserVotedSuggestions(userId);

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

  // Bulk update suggestions (admin only)
  bulkUpdateSuggestions: catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userId = req.user?.id;
      const { suggestion_ids, status, assigned_to, estimated_release_date } =
        req.body;

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

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

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

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

      if (suggestion_ids.length > 100) {
        return next(
          new ErrorHandler(
            "Cannot update more than 100 suggestions at once",
            400,
          ),
        );
      }

      const updateData: any = {};
      if (status) updateData.status = status;
      if (assigned_to) updateData.assigned_to = assigned_to;
      if (estimated_release_date)
        updateData.estimated_release_date = estimated_release_date;

      try {
        const updatedSuggestions =
          await productSuggestedFeatureService.bulkUpdateSuggestions(
            suggestion_ids,
            updateData,
          );

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

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

      const roadmap =
        await productSuggestedFeatureService.getProductRoadmap(productId);

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

  // Get completed features
  getCompletedFeatures: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { productId } = req.params;
      const limit = parseInt(req.query.limit as string) || 20;

      const completedFeatures =
        await productSuggestedFeatureService.getCompletedFeatures(
          productId,
          limit,
        );

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

  // Get similar suggestions
  getSimilarSuggestions: catchAsyncError(
    async (req: Request, res: Response, next: NextFunction) => {
      const { id } = req.params;
      const limit = parseInt(req.query.limit as string) || 5;

      const suggestion =
        await productSuggestedFeatureService.getFeatureSuggestionById(
          id,
          false,
        );
      if (!suggestion) {
        return next(new ErrorHandler("Suggestion not found", 404));
      }

      // Find similar suggestions based on tags and title
      const query = `
      WITH target_suggestion AS (
        SELECT product_id, tags, title
        FROM products_suggested_features
        WHERE id = $1
      )
      SELECT 
        f.*,
        suggestor.username as suggestor_username,
        suggestor.display_name as suggestor_display_name,
        (
          -- Calculate similarity score
          (CASE WHEN f.tags && ts.tags THEN array_length(f.tags & ts.tags, 1) * 2 ELSE 0 END) +
          (CASE WHEN f.title ILIKE '%' || split_part(ts.title, ' ', 1) || '%' THEN 3 ELSE 0 END) +
          (CASE WHEN f.title ILIKE '%' || split_part(ts.title, ' ', 2) || '%' THEN 2 ELSE 0 END)
        ) as similarity_score
      FROM products_suggested_features f, target_suggestion ts
      LEFT JOIN accounts suggestor ON f.suggestor_id = suggestor.id
      WHERE f.id != $1
        AND f.product_id = ts.product_id
        AND f.status IN ('suggested', 'under-review')
      ORDER BY similarity_score DESC, f.upvotes DESC
      LIMIT $2;
    `;

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

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

  // Get suggestion activity
  getSuggestionActivity: 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));
      }

      // Check if user has permission
      const suggestion =
        await productSuggestedFeatureService.getFeatureSuggestionById(
          id,
          false,
        );
      if (!suggestion) {
        return next(new ErrorHandler("Suggestion not found", 404));
      }

      const isOwner = suggestion.suggestor_id === userId;
      const isProductOwner = await checkProductOwner(
        suggestion.product_id,
        userId,
      );
      const isAdmin = req.user?.roles?.some((role: any) =>
        ["admin", "super_admin"].includes(role.name),
      );

      if (!isOwner && !isProductOwner && !isAdmin) {
        return next(
          new ErrorHandler("You don't have permission to view activity", 403),
        );
      }

      // Get activity from various sources (you might have an activity table)
      const activityQuery = `
      SELECT 
        'vote' as type,
        unnest(unique_voters) as user_id,
        created_at as timestamp,
        'User voted on suggestion' as description
      FROM products_suggested_features
      WHERE id = $1
      UNION ALL
      SELECT 
        'status_change' as type,
        NULL as user_id,
        status_changed_at as timestamp,
        'Status changed to ' || status as description
      FROM products_suggested_features
      WHERE id = $1 AND status_changed_at IS NOT NULL
      UNION ALL
      SELECT 
        'update' as type,
        NULL as user_id,
        updated_at as timestamp,
        'Suggestion was updated' as description
      FROM products_suggested_features
      WHERE id = $1
      ORDER BY timestamp DESC;
    `;

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

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

};

// Helper function to check if user is product owner
async function checkProductOwner(productId: string, userId: string): Promise<boolean> {
  const result = await database.query(
    `SELECT creator_id FROM products WHERE id = $1`,
    [productId],
  );
  return result.rows.length > 0 && result.rows[0].creator_id === userId;
}
