import { Request, Response, NextFunction } from "express";
import { catchAsyncError } from "../../middlewares/catchAsyncError";
import ErrorHandler from "../../middlewares/error";
import { 
  productGalleryService, 
  GalleryCreateData,
  GalleryFilters  
} from "./product.gallery.service";
import { AuthRequest } from "../../middlewares/auth";
import { uploadFile, deleteFile } from "../../utils/cloudStorage";
import { database } from "../../config/db"; 

export const productGalleryController = {
  // Upload single gallery item
  uploadGalleryItem: catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
    const userId = req.user?.id;
     
    if (!userId) {
      return next(new ErrorHandler("Authentication required", 401));
    }

    const { product_id, type = "image", caption, is_featured, is_primary } = req.body;
    
    if (!product_id) {
      return next(new ErrorHandler("Product ID is required", 400));
    }

    if (!req.files || !req.files.file) {
      return next(new ErrorHandler("File is required", 400));
    }

    // Check if user owns the product
    const productCheck = await database.query(
      `SELECT creator_id FROM products WHERE id = $1`,
      [product_id]
    );

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

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

    if (!isProductOwner && !isAdmin) {
      return next(new ErrorHandler("You can only upload gallery items for your own products", 403));
    }

    const file = Array.isArray(req.files.file) ? req.files.file[0] : req.files.file;

    try {
      // Upload to Cloudinary
      const uploadResult = await uploadFile(
        file,
        "product-gallery",
        userId
      );

      // Create thumbnail (you might want to create different sizes)
      const thumbnailResult = {
        ...uploadResult,
        url: uploadResult.url.replace("/upload/", "/upload/w_300,h_300,c_fill/"),
      };

      const galleryData: GalleryCreateData = {
        product_id,
        url: {
          url: uploadResult.url,
          public_id: uploadResult.public_id,
          format: uploadResult.format,
          size: uploadResult.size,
          width: uploadResult.width,
          height: uploadResult.height,
        },
        thumbnail: {
          url: thumbnailResult.url,
          public_id: uploadResult.public_id,
          format: uploadResult.format,
          size: uploadResult.size,
          width: 300,
          height: 300,
        },
        type,
        media_format: uploadResult.format,
        caption,
        public_id: uploadResult.public_id,
        resource_type: type === "video" ? "video" : "image",
        is_featured: is_featured === "true",
        is_primary: is_primary === "true",
      };

      const galleryItem = await productGalleryService.uploadGalleryItem(galleryData);

      res.status(201).json({
        success: true,
        message: "Gallery item uploaded successfully",
        data: galleryItem,
      });
    } catch (error: any) {
      return next(new ErrorHandler(error.message, 400));
    }
  }),

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

    const galleryItem = await productGalleryService.getGalleryItemById(id);
    
    if (!galleryItem) {
      return next(new ErrorHandler("Gallery item not found", 404));
    }

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

  // Get all gallery items for a product
  getProductGallery: catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
    const { productId } = req.params;
    const {
      page = 1,
      limit = 50,
      type,
      status = "active",
      is_featured,
      is_primary,
      sort_by = "display_order",
      order = "asc",
    } = req.query;

    const filters: GalleryFilters = {
      page: parseInt(page as string),
      limit: parseInt(limit as string),
      product_id: productId,
      type: type as string,
      status: status as string,
      is_featured: is_featured ? is_featured === "true" : undefined,
      is_primary: is_primary ? is_primary === "true" : undefined,
      sort_by: sort_by as string,
      order: order as "asc" | "desc",
    };

    const result = await productGalleryService.getProductGallery(productId, filters);

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

  // Get featured gallery items
  getFeaturedGallery: catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
    const { productId } = req.params;
    const limit = parseInt(req.query.limit as string) || 3;

    const featuredItems = await productGalleryService.getFeaturedGallery(productId, limit);

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

  // Get primary image
  getPrimaryImage: catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
    const { productId } = req.params;

    const primaryImage = await productGalleryService.getPrimaryImage(productId);
    
    if (!primaryImage) {
      return next(new ErrorHandler("No primary image found", 404));
    }

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

  // Update gallery item
  updateGalleryItem: 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 updatedItem = await productGalleryService.updateGalleryItem(id, data, userId);

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

  // Delete gallery item
  deleteGalleryItem: 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 deletedItem = await productGalleryService.deleteGalleryItem(id, userId);

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

  // Reorder gallery items
  reorderGalleryItems: catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
    const { productId } = req.params;
    const userId = req.user?.id;
    const { item_ids } = req.body;

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

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

    // Check if user owns the product
    const productCheck = await database.query(
      `SELECT creator_id FROM products WHERE id = $1`,
      [productId]
    );

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

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

    if (!isProductOwner && !isAdmin) {
      return next(new ErrorHandler("You can only reorder gallery items for your own products", 403));
    }

    try {
      const reorderedItems = await productGalleryService.reorderGalleryItems(productId, item_ids);

      res.status(200).json({
        success: true,
        message: "Gallery items reordered successfully",
        data: reorderedItems,
      });
    } catch (error: any) {
      return next(new ErrorHandler(error.message, 400));
    }
  }),

  // Set featured items
  setFeaturedItems: catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
    const { productId } = req.params;
    const userId = req.user?.id;
    const { item_ids } = req.body;

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

    if (!Array.isArray(item_ids)) {
      return next(new ErrorHandler("Item IDs array is required", 400));
    }

    if (item_ids.length > 3) {
      return next(new ErrorHandler("Maximum 3 featured items allowed", 400));
    }

    try {
      const featuredItems = await productGalleryService.setFeaturedItems(productId, item_ids, userId);

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

  // Set primary image
  setPrimaryImage: catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
    const { productId } = req.params;
    const userId = req.user?.id;
    const { item_id } = req.body;

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

    if (!item_id) {
      return next(new ErrorHandler("Item ID is required", 400));
    }

    try {
      const primaryImage = await productGalleryService.setPrimaryImage(productId, item_id, userId);

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

  // Upload multiple gallery items
  uploadMultipleItems: catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
    const userId = req.user?.id;
    const { product_id, items } = req.body;
    
    if (!userId) {
      return next(new ErrorHandler("Authentication required", 401));
    }

    if (!product_id) {
      return next(new ErrorHandler("Product ID is required", 400));
    }

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

    try {
      const result = await productGalleryService.uploadMultipleItems(product_id, items, userId);

      res.status(201).json({
        success: true,
        message: "Gallery items uploaded successfully",
        data: result,
      });
    } catch (error: any) {
      return next(new ErrorHandler(error.message, 400));
    }
  }),

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

    const stats = await productGalleryService.getGalleryStats(productId);
    
    res.status(200).json({
      success: true,
      data: stats,
    });
  }),

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

    const validTypes = ["image", "video", "youtube", "vimeo", "gif"];
    if (!validTypes.includes(type)) {
      return next(new ErrorHandler(`Invalid type. Must be one of: ${validTypes.join(", ")}`, 400));
    }

    const galleryItems = await productGalleryService.getGalleryByType(productId, type);

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

  // Update product logo from primary image
  updateProductLogoFromPrimary: 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));
    }

    try {
      const result = await productGalleryService.updateProductLogoFromPrimary(productId, userId);

      res.status(200).json({
        success: true,
        message: "Product logo updated from primary image",
        data: result,
      });
    } catch (error: any) {
      return next(new ErrorHandler(error.message, error.message.includes("own") ? 403 : 400));
    }
  }),

  // Bulk delete gallery items
  bulkDeleteGalleryItems: catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
    const userId = req.user?.id;
    const { item_ids } = req.body;

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

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

    if (item_ids.length > 50) {
      return next(new ErrorHandler("Maximum 50 items can be deleted at once", 400));
    }

    try {
      const result = await productGalleryService.bulkDeleteGalleryItems(item_ids, userId);

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

  // Direct Cloudinary upload endpoint
  directUpload: catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
    const userId = req.user?.id;
    
    if (!userId) {
      return next(new ErrorHandler("Authentication required", 401));
    }

    if (!req.files || !req.files.file) {
      return next(new ErrorHandler("File is required", 400));
    }

    const file = Array.isArray(req.files.file) ? req.files.file[0] : req.files.file;
    const { folder = "product-gallery", transformation } = req.body;

    try {
      const uploadResult = await uploadFile(
        file,
        folder,
        userId,
        // transformation ? JSON.parse(transformation) : undefined
      );

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