import { useState, useEffect } from "react";
import { 
  DragEndEvent, 
  DragStartEvent, 
  DragMoveEvent, 
  CollisionDetection,
  pointerWithin,
  rectIntersection
} from '@dnd-kit/core';
import { arrayMove } from '@dnd-kit/sortable';
import { toast } from "sonner";
import { ProductImageSortable } from "../types";

type UseDragAndDropProps = {
  productImages: ProductImageSortable[];
  setProductImages: React.Dispatch<React.SetStateAction<ProductImageSortable[]>>;
  data: any[];
};

type UseDragAndDropReturn = {
  activeId: string | null;
  activeImage: ProductImageSortable | null;
  activeDroppableId: string | null;
  customCollisionDetection: CollisionDetection;
  findContainer: (id: string) => string | null;
  getProductImages: (productIndex: number) => ProductImageSortable[];
  getProductContainerClasses: (index: number) => string;
  handleDragStart: (event: DragStartEvent) => void;
  handleDragOver: (event: DragMoveEvent) => void;
  handleDragEnd: (event: DragEndEvent) => void;
};

export const useDragAndDrop = ({ 
  productImages, 
  setProductImages, 
  data 
}: UseDragAndDropProps): UseDragAndDropReturn => {
  const [activeId, setActiveId] = useState<string | null>(null);
  const [activeImage, setActiveImage] = useState<ProductImageSortable | null>(null);
  const [activeDroppableId, setActiveDroppableId] = useState<string | null>(null);

  // Custom collision detection algorithm that prioritizes product containers
  const customCollisionDetection: CollisionDetection = (args) => {
    // Use the built-in pointerWithin algorithm first for better performance
    const pointerCollisions = pointerWithin(args);
    
    if (pointerCollisions.length > 0) {
      return pointerCollisions;
    }
    
    // Fall back to rectIntersection if no pointer collisions
    return rectIntersection(args);
  };

  // Function to find container (productIndex) an image belongs to
  const findContainer = (id: string) => {
    const image = productImages.find(img => img.id === id);
    return image ? image.productIndex.toString() : null;
  };

  // Function to get images for a specific product
  const getProductImages = (productIndex: number) => {
    return productImages.filter(img => img.productIndex === productIndex);
  };

  // Handle drag start to set active image and prevent default behavior
  const handleDragStart = (event: DragStartEvent) => {
    const { active } = event;
    
    const activeImageItem = productImages.find(img => img.id === active.id);
    setActiveId(active.id.toString());
    if (activeImageItem) {
      setActiveImage(activeImageItem);
    }
  };

  // Handle drag over to track which product container is being hovered
  const handleDragOver = (event: DragMoveEvent) => {
    const { over } = event;
    
    if (!over) {
      setActiveDroppableId(null);
      return;
    }
    
    let overContainer = null;
    
    // Check if we're over a product container directly
    if (typeof over.id === 'string' && over.id.toString().startsWith('product-')) {
      overContainer = over.id.toString();
      setActiveDroppableId(overContainer);
    } 
    // Otherwise check if we're over another image
    else {
      const overImage = productImages.find(img => img.id === over.id);
      if (overImage) {
        overContainer = `product-${overImage.productIndex}`;
        setActiveDroppableId(overContainer);
      } else {
        setActiveDroppableId(null);
      }
    }
  };

  // Update handleDragEnd to work with the updated product data structure
  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    
    // Reset active droppable
    setActiveDroppableId(null);
    
    if (!over) {
      setActiveId(null);
      setActiveImage(null);
      return;
    }
    
    const activeId = active.id;
    const overId = over.id;
    
    // Find the containers (product indices) for the active element
    const activeContainer = findContainer(activeId.toString());
    let overContainer = null;
    
    // Check if overId is a product container directly
    if (typeof overId === 'string' && overId.toString().startsWith('product-')) {
      overContainer = overId.toString().split('-')[1];
    } 
    // Otherwise check if it's an image, so find its container
    else {
      overContainer = findContainer(overId.toString());
    }
    
    // If we couldn't determine active container, do nothing
    if (!activeContainer) {
      setActiveId(null);
      setActiveImage(null);
      return;
    }

    // If we couldn't determine the over container, do nothing
    if (!overContainer) {
      setActiveId(null);
      setActiveImage(null);
      return;
    }

    // Convert containers to numbers
    const sourceProductIndex = parseInt(activeContainer);
    const targetProductIndex = parseInt(overContainer);
    
    // Find the active image
    const activeImage = productImages.find(img => img.id === activeId);
    if (!activeImage) {
      setActiveId(null);
      setActiveImage(null);
      return;
    }
    
    // IMPORTANT: If source and target are different products, ALWAYS prioritize moving over reordering
    if (sourceProductIndex !== targetProductIndex) {
      // Create a copy of the image with the new product index
      const newImage: ProductImageSortable = {
        ...activeImage,
        productIndex: targetProductIndex,
        // Generate a new ID for the image in its new location
        id: `image-${targetProductIndex}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
      };
      
      // Remove the image from the source product and add to target product
      setProductImages(items => {
        // Remove the image from its current product
        const filteredItems = items.filter(item => item.id !== activeId);
        
        // Add the image to the target product
        filteredItems.push(newImage);
        
        // Show notification
        toast.success(`Image moved from ${data[sourceProductIndex].name || `Product #${sourceProductIndex + 1}`} to ${data[targetProductIndex].name || `Product #${targetProductIndex + 1}`}`);
        
        return filteredItems;
      });
    }
    // Source and target are the same product - this is a reordering operation
    else {
      // Only attempt reordering if we have at least 2 images in this container
      const productImages = getProductImages(sourceProductIndex);
      
      if (productImages.length >= 2) {
        // Handle reordering regardless of whether we're over a container or another image
        setProductImages(items => {
          // Filter to get only the images for this product
          const productFilteredItems = items.filter(item => item.productIndex === sourceProductIndex);
          
          // If dropping onto the container itself, put at the end
          if (overId.toString().startsWith('product-')) {
            // Find active index
            const activeIndex = productFilteredItems.findIndex(item => item.id === activeId);
            
            if (activeIndex === -1) {
              return items; // No change needed
            }
            
            // Move active item to end (remove and push to end)
            const newFilteredItems = [...productFilteredItems];
            const [movedItem] = newFilteredItems.splice(activeIndex, 1);
            newFilteredItems.push(movedItem);
            
            // Create a new full list replacing the items for this product with the reordered ones
            const newItems = items.filter(item => item.productIndex !== sourceProductIndex);
            newItems.push(...newFilteredItems);
            
            return newItems;
          }
          
          // Find indices within the filtered list
          const activeIndex = productFilteredItems.findIndex(item => item.id === activeId);
          const overIndex = productFilteredItems.findIndex(item => item.id === overId);
          
          // If one of the indices is not found or they're the same, do nothing
          if (activeIndex === -1 || overIndex === -1 || activeIndex === overIndex) {
            return items;
          }
          
          // Reorder the filtered items
          const newFilteredItems = arrayMove(productFilteredItems, activeIndex, overIndex);
          
          // Create a new full list replacing the items for this product with the reordered ones
          const newItems = items.filter(item => item.productIndex !== sourceProductIndex);
          newItems.push(...newFilteredItems);
          
          return newItems;
        });
      }
    }
    
    setActiveId(null);
    setActiveImage(null);
  };

  // Monitor drag events to prevent browser behaviors
  useEffect(() => {
    // Add a global event listener to prevent browser's native drag behavior
    const preventDefaultDragImage = (event: DragEvent) => {
      if (activeId) {
        event.preventDefault();
      }
    };

    document.addEventListener('dragstart', preventDefaultDragImage);
    
    return () => {
      document.removeEventListener('dragstart', preventDefaultDragImage);
    };
  }, [activeId]);

  // Add product IDs to the valid droppable elements
  useEffect(() => {
    // Add data-droppable attributes to make product containers easier to identify
    data.forEach((_, index) => {
      const container = document.getElementById(`product-${index}`);
      if (container) {
        container.setAttribute('data-droppable', 'true');
        container.setAttribute('aria-dropeffect', 'move');
        
        // Check if the container has images
        const hasImages = getProductImages(index).length > 0;
        
        // Set data-empty attribute for tracking purposes
        container.setAttribute('data-empty', hasImages ? 'false' : 'true');
        
        // Ensure the container has sufficient size to be a drop target
        if (container.offsetHeight < 100) {
          container.style.minHeight = '100px';
        }
      }
    });
  }, [data, productImages]); // Add productImages as a dependency to re-run when images change

  // Effect to register browser-level drag events on product containers
  useEffect(() => {
    // For each product container
    data.forEach((_, index) => {
      const container = document.getElementById(`product-${index}`);
      
      if (container) {
        // Define handlers for native browser drag events
        const handleNativeDragOver = (e: DragEvent) => {
          e.preventDefault();
          setActiveDroppableId(`product-${index}`);
        };
        
        const handleNativeDragLeave = () => {
          if (activeDroppableId === `product-${index}`) {
            setActiveDroppableId(null);
          }
        };
        
        // Add these handlers
        container.addEventListener('dragover', handleNativeDragOver);
        container.addEventListener('dragleave', handleNativeDragLeave);
        
        // Return cleanup function
        return () => {
          container.removeEventListener('dragover', handleNativeDragOver);
          container.removeEventListener('dragleave', handleNativeDragLeave);
        };
      }
    });
  }, [data, productImages, activeDroppableId]); // Re-run when data or productImages change

  // Function to add more visual indication when dragging
  const getProductContainerClasses = (index: number) => {
    const isValidDropTarget = activeId && findContainer(activeId) !== index.toString();
    const isActiveDropTarget = activeDroppableId === `product-${index}`;
    
    return [
      "flex-1 min-h-[6rem] rounded-md p-2 transition-all",
      // Only show borders during active drag operations
      isValidDropTarget && isActiveDropTarget 
        ? "border-2 border-dashed border-primary bg-primary/10" 
        : isValidDropTarget
          ? "border border-dashed border-muted-foreground/30"
          : ""
    ].filter(Boolean).join(" ");
  };

  return {
    activeId,
    activeImage,
    activeDroppableId,
    customCollisionDetection,
    findContainer,
    getProductImages,
    getProductContainerClasses,
    handleDragStart,
    handleDragOver,
    handleDragEnd
  };
}; 