"use client";

import { useState, useEffect, useRef } from "react";
import Layout from "@/components/layout/layout";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Plus, Pencil, Trash2, ChevronRight, ChevronDown, MoveVertical, FolderTree } from "lucide-react";
import { toast } from "sonner";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { apiRequest } from "@/lib/api";
import type { Category } from "@/models/categories";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

// Drag and Drop imports
import { DndProvider, useDrag, useDrop, DropTargetMonitor } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';

// Define interfaces for drag item
interface DragItem {
  id: string;
  parentId?: string;
}

// Item Types
const ItemTypes = {
  CATEGORY: 'category',
};

export default function CategoriesPage() {
  const [categories, setCategories] = useState<Category[]>([]);
  const [newCategoryName, setNewCategoryName] = useState("");
  const [selectedParentId, setSelectedParentId] = useState<string>("");
  const [editingCategory, setEditingCategory] = useState<Category | null>(null);
  const [categoryToDelete, setCategoryToDelete] = useState<Category | null>(null);
  const [expanded, setExpanded] = useState<Record<string, boolean>>({});

  // Get root categories sorted by order
  const rootCategories = categories
    .filter(cat => !cat.parentId)
    .sort((a, b) => (a.order || 0) - (b.order || 0));
  
  // Get subcategories sorted by order
  const getSubcategories = (parentId: string) => 
    categories
      .filter(cat => cat.parentId === parentId)
      .sort((a, b) => (a.order || 0) - (b.order || 0));

  useEffect(() => {
    fetchCategories();
  }, []);

  const fetchCategories = async () => {
    try {
      const fetchedCategories = await apiRequest("/categories", "GET");
      setCategories(fetchedCategories);
    } catch (error) {
      toast.error("Failed to fetch categories");
    }
  };

  const handleAddCategory = async () => {
    if (!newCategoryName.trim()) {
      toast.error("Category name cannot be empty");
      return;
    }

    try {
      // Find the highest order in the selected parent group
      const siblings = selectedParentId 
        ? categories.filter(cat => cat.parentId === selectedParentId)
        : categories.filter(cat => !cat.parentId);
      
      const maxOrder = siblings.reduce((max, cat) => 
        Math.max(max, cat.order || 0), 0);
      
      const response = await apiRequest("/categories", "POST", {
        name: newCategoryName,
        parentId: selectedParentId || undefined,
        order: maxOrder + 1,
      });

      setCategories([...categories, response]);
      setNewCategoryName("");
      setSelectedParentId("");
      toast.success("Category added successfully");
    } catch (error) {
      toast.error("Failed to add category");
    }
  };

  const handleUpdateCategory = async (categoryId: string, newName: string) => {
    try {
      const response = await apiRequest(`/categories/${categoryId}`, "PUT", {
        name: newName,
      });

      setCategories(categories.map(cat => 
        cat._id === categoryId ? { ...cat, name: newName } : cat
      ));
      setEditingCategory(null);
      toast.success("Category updated successfully");
    } catch (error) {
      toast.error("Failed to update category");
    }
  };

  const handleDeleteConfirm = async () => {
    if (!categoryToDelete) return;

    try {
      await apiRequest(`/categories/${categoryToDelete._id}`, "DELETE");
      setCategories(categories.filter(cat => cat._id !== categoryToDelete._id));
      toast.success("Category deleted successfully");
      setCategoryToDelete(null);
    } catch (error) {
      console.error("Failed to delete category:", error);
      toast.error("Failed to delete category");
    }
  };

  const moveCategory = async (dragId: string, hoverId: string, parentId?: string) => {
    // Create new array with updated orders
    const dragIndex = categories.findIndex(cat => cat._id === dragId);
    const hoverIndex = categories.findIndex(cat => cat._id === hoverId);
    
    if (dragIndex === -1 || hoverIndex === -1) return;
    
    const draggedCategory = categories[dragIndex];
    
    // Make sure we're only reordering within the same parent group
    if (draggedCategory.parentId !== parentId) return;
    
    // Create a copy for reordering
    const updatedCategories = [...categories];
    
    // Get only categories with the same parent for reordering
    const siblingCategories = updatedCategories
      .filter(cat => cat.parentId === parentId)
      .sort((a, b) => (a.order || 0) - (b.order || 0));
    
    // Remove the dragged category from its position
    const draggedItem = siblingCategories.find(cat => cat._id === dragId);
    if (!draggedItem) return;
    
    const filteredSiblings = siblingCategories.filter(cat => cat._id !== dragId);
    
    // Find where to insert the dragged item
    const hoverItem = siblingCategories.find(cat => cat._id === hoverId);
    if (!hoverItem) return;
    
    const hoverPos = filteredSiblings.findIndex(cat => cat._id === hoverId);
    
    // Insert the dragged item at the new position
    filteredSiblings.splice(hoverPos, 0, draggedItem);
    
    // Update the order for all siblings
    filteredSiblings.forEach((cat, index) => {
      cat.order = index;
    });
    
    // Update the categories state
    setCategories(updatedCategories.map(cat => {
      const updatedCat = filteredSiblings.find(c => c._id === cat._id);
      return updatedCat || cat;
    }));
    
    // Save the new order to the server using bulk update
    try {
      const categoriesToUpdate = filteredSiblings.map(cat => ({
        _id: cat._id,
        order: cat.order
      }));
      
      await apiRequest("/categories/bulk-order", "PUT", {
        categories: categoriesToUpdate
      });
    } catch (error) {
      toast.error("Failed to update category order");
      // Revert to original order
      fetchCategories();
    }
  };

  const toggleExpand = (categoryId: string) => {
    setExpanded(prev => ({
      ...prev,
      [categoryId]: !prev[categoryId]
    }));
  };

  // Category Item Component with Drag & Drop
  const CategoryItem = ({ category, level = 0 }: { category: Category, level?: number }) => {
    const subcategories = getSubcategories(category._id);
    const hasSubcategories = subcategories.length > 0;
    const isEditing = editingCategory?._id === category._id;
    const isExpanded = expanded[category._id];
    
    const ref = useRef<HTMLDivElement>(null);
    
    // Set up drag
    const [{ isDragging }, drag] = useDrag({
      type: ItemTypes.CATEGORY,
      item: { id: category._id, parentId: category.parentId },
      collect: (monitor) => ({
        isDragging: monitor.isDragging(),
      }),
    });
    
    // Set up drop
    const [{ handlerId, isOver }, drop] = useDrop<DragItem, void, { handlerId: string | symbol | null; isOver: boolean }>({
      accept: ItemTypes.CATEGORY,
      collect: (monitor) => ({
        handlerId: monitor.getHandlerId(),
        isOver: monitor.isOver(),
      }),
      hover(item: DragItem, monitor) {
        if (!ref.current) return;
        
        const dragId = item.id;
        const hoverId = category._id;
        
        // Don't replace items with themselves
        if (dragId === hoverId) return;
        
        // Only allow reordering within the same parent
        if (item.parentId !== category.parentId) return;
        
        moveCategory(dragId, hoverId, category.parentId);
      },
    });
    
    // Connect the drag and drop refs
    drag(drop(ref));
    
    return (
      <div key={category._id} className="space-y-1">
        <div 
          ref={ref}
          className={`group flex items-center p-2 rounded-md transition-colors
            ${isEditing ? 'bg-gray-100 dark:bg-gray-800' : ''}
            ${isOver ? 'bg-gray-100 dark:bg-gray-800' : 'hover:bg-gray-100 dark:hover:bg-gray-800'}
            ${isDragging ? 'opacity-50' : 'opacity-100'}`}
          style={{ marginLeft: `${level * 24}px` }}
          data-handler-id={handlerId}
        >
          <div className="cursor-grab mr-2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
            <MoveVertical className="h-4 w-4" />
          </div>
          
          {hasSubcategories && (
            <button 
              onClick={() => toggleExpand(category._id)}
              className="mr-1 focus:outline-none"
            >
              {isExpanded ? 
                <ChevronDown className="h-4 w-4 text-muted-foreground" /> : 
                <ChevronRight className="h-4 w-4 text-muted-foreground" />
              }
            </button>
          )}
          
          <div className="flex-1 flex items-center space-x-2">
            {isEditing ? (
              <Input
                value={editingCategory?.name || ""}
                onChange={(e) => setEditingCategory(prev => prev ? { ...prev, name: e.target.value } : prev)}
                className="h-8 max-w-[200px]"
                autoFocus
                onKeyDown={(e) => {
                  if (e.key === 'Enter' && editingCategory) {
                    handleUpdateCategory(category._id, editingCategory.name);
                  } else if (e.key === 'Escape') {
                    setEditingCategory(null);
                  }
                }}
              />
            ) : (
              <span className="text-sm font-medium">{category.name}</span>
            )}
          </div>
          <div className="flex items-center space-x-1 opacity-0 group-hover:opacity-100 transition-opacity">
            {isEditing ? (
              <>
                <Button
                  size="sm"
                  variant="ghost"
                  className="h-8 px-2 text-green-600 hover:text-green-700 hover:bg-green-50"
                  onClick={() => editingCategory && handleUpdateCategory(category._id, editingCategory.name)}
                >
                  Save
                </Button>
                <Button
                  size="sm"
                  variant="ghost"
                  className="h-8 px-2"
                  onClick={() => setEditingCategory(null)}
                >
                  Cancel
                </Button>
              </>
            ) : (
              <>
                <Button
                  size="sm"
                  variant="ghost"
                  className="h-8 w-8 p-0 text-blue-500 hover:text-blue-600 hover:bg-blue-50"
                  onClick={() => setEditingCategory(category)}
                >
                  <Pencil className="h-4 w-4" />
                </Button>
                <Button
                  size="sm"
                  variant="ghost"
                  className="h-8 w-8 p-0 text-red-500 hover:text-red-600 hover:bg-red-50"
                  onClick={() => setCategoryToDelete(category)}
                >
                  <Trash2 className="h-4 w-4" />
                </Button>
              </>
            )}
          </div>
        </div>
        {isExpanded && subcategories.map(subcat => 
          <CategoryItem key={subcat._id} category={subcat} level={level + 1} />
        )}
      </div>
    );
  };

  return (
    <Layout>
      <div className="space-y-6">
        <div className="flex items-center justify-between">
          <h1 className="text-2xl font-semibold text-gray-900 dark:text-white flex items-center">
            <FolderTree className="mr-2 h-6 w-6" />
            Categories
          </h1>
        </div>

        <div className="grid grid-cols-1 lg:grid-cols-3 xl:grid-cols-5 gap-4 lg:gap-6">
          {/* Add Category Card - Takes up 2 columns */}
          <Card className="lg:col-span-2">
            <CardHeader>
              <CardTitle className="text-lg font-medium">Add New Category</CardTitle>
            </CardHeader>
            <CardContent>
              <div className="space-y-4">
                <div className="space-y-2">
                  <label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
                    Category Name
                  </label>
                  <Input
                    value={newCategoryName}
                    onChange={(e) => setNewCategoryName(e.target.value)}
                    placeholder="Enter category name"
                    className="h-9"
                  />
                </div>
                <div className="space-y-2">
                  <label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
                    Parent Category
                  </label>
                  <Select
                    value={selectedParentId || "none"}
                    onValueChange={setSelectedParentId}
                  >
                    <SelectTrigger className="h-9">
                      <SelectValue placeholder="Select parent category" />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="none">No parent (root category)</SelectItem>
                      {categories.map((cat) => (
                        <SelectItem key={cat._id} value={cat._id}>
                          {cat.name}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
                <Button onClick={handleAddCategory} className="w-full">
                  <Plus className="h-4 w-4 mr-2" />
                  Add Category
                </Button>
              </div>
            </CardContent>
          </Card>

          {/* Category List Card - Takes up 3 columns */}
          <Card className="lg:col-span-3">
            <CardHeader>
              <CardTitle className="text-lg font-medium">Category List</CardTitle>
            </CardHeader>
            <CardContent>
              <DndProvider backend={HTML5Backend}>
                <div className="space-y-1">
                  {rootCategories.length === 0 ? (
                    <p className="text-sm text-muted-foreground text-center py-4">
                      No categories yet. Add your first category above.
                    </p>
                  ) : (
                    rootCategories.map(category => (
                      <CategoryItem key={category._id} category={category} />
                    ))
                  )}
                </div>
              </DndProvider>
            </CardContent>
          </Card>
        </div>
        
        {/* Delete Confirmation Dialog */}
        {categoryToDelete && (
          <AlertDialog open={!!categoryToDelete} onOpenChange={() => setCategoryToDelete(null)}>
            <AlertDialogContent>
              <AlertDialogHeader>
                <AlertDialogTitle>Are you sure?</AlertDialogTitle>
                <AlertDialogDescription>
                  This will permanently delete the category "{categoryToDelete.name}".
                  This action cannot be undone.
                </AlertDialogDescription>
              </AlertDialogHeader>
              <AlertDialogFooter>
                <AlertDialogCancel>Cancel</AlertDialogCancel>
                <AlertDialogAction onClick={handleDeleteConfirm}>Delete</AlertDialogAction>
              </AlertDialogFooter>
            </AlertDialogContent>
          </AlertDialog>
        )}
      </div>
    </Layout>
  );
} 