"use client";

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

// 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>>({});
  const [loading, setLoading] = useState(true);

  // 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 {
      setLoading(true);
      const fetchedCategories = await apiRequest("/categories", "GET");
      setCategories(fetchedCategories);
    } catch (error) {
      toast.error("Failed to fetch categories");
    } finally {
      setLoading(false);
    }
  };

  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 (
      <motion.div
        key={category._id}
        initial={{ opacity: 0, y: 5 }}
        animate={{ opacity: 1, y: 0 }}
        exit={{ opacity: 0 }}
        className="space-y-1"
      >
        <div
          ref={ref}
          className={`group flex items-center p-3 rounded-xl transition-all duration-200 border mb-2
            ${isEditing ? 'bg-indigo-500/10 border-indigo-500/30' : ''}
            ${isOver ? 'bg-indigo-500/20 border-indigo-500/50 scale-[1.02]' : 'bg-black/40 border-white/5 hover:bg-black/60 hover:border-white/10 hover:shadow-lg'}
            ${isDragging ? 'opacity-30' : 'opacity-100'} backdrop-blur-sm`}
          style={{ marginLeft: `${level * 24}px` }}
          data-handler-id={handlerId}
        >
          <div className="cursor-grab mr-2 text-muted-foreground/40 hover:text-muted-foreground transition-colors">
            <MoveVertical className="h-4 w-4" />
          </div>

          {hasSubcategories ? (
            <button
              onClick={() => toggleExpand(category._id)}
              className="mr-1 focus:outline-none p-0.5 rounded-sm hover:bg-muted text-muted-foreground transition-colors"
            >
              {isExpanded ?
                <ChevronDown className="h-4 w-4" /> :
                <ChevronRight className="h-4 w-4" />
              }
            </button>
          ) : (
            <div className="w-6 h-5" /> // Spacer
          )}

          <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] border-primary/30 focus-visible:ring-primary/20"
                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-500/10"
                  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="icon"
                  variant="ghost"
                  className="h-8 w-8 text-muted-foreground hover:text-primary hover:bg-primary/10 transition-colors"
                  onClick={() => setEditingCategory(category)}
                >
                  <Pencil className="h-3.5 w-3.5" />
                </Button>
                <Button
                  size="icon"
                  variant="ghost"
                  className="h-8 w-8 text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors"
                  onClick={() => setCategoryToDelete(category)}
                >
                  <Trash2 className="h-3.5 w-3.5" />
                </Button>
              </>
            )}
          </div>
        </div>
        <AnimatePresence>
          {isExpanded && hasSubcategories && (
            <motion.div
              initial={{ opacity: 0, height: 0 }}
              animate={{ opacity: 1, height: "auto" }}
              exit={{ opacity: 0, height: 0 }}
              transition={{ duration: 0.2 }}
            >
              {subcategories.map(subcat =>
                <CategoryItem key={subcat._id} category={subcat} level={level + 1} />
              )}
            </motion.div>
          )}
        </AnimatePresence>
      </motion.div>
    );
  };

  return (
    <Layout>
      <div className="space-y-8 animate-in fade-in duration-500">
        <div className="flex items-center justify-between">
          <div>
            <h1 className="text-2xl font-semibold text-foreground flex items-center">
              <FolderTree className="mr-3 h-6 w-6 text-primary" />
              Categories
            </h1>
            <p className="text-muted-foreground text-sm mt-1">
              Manage your product categories and hierarchy
            </p>
          </div>
        </div>

        <div className="grid grid-cols-1 lg:grid-cols-3 xl:grid-cols-5 gap-6 lg:gap-8">
          {/* Add Category Card */}
          <Card className="lg:col-span-2 border-white/10 bg-black/40 backdrop-blur-xl shadow-xl h-fit sticky top-6 rounded-xl overflow-hidden">
            <CardHeader className="bg-white/[0.02] border-b border-white/5 pb-4">
              <CardTitle className="text-lg font-bold flex items-center text-white">
                <div className="p-2 mr-3 rounded-lg bg-indigo-500/10 border border-indigo-500/20">
                  <Plus className="h-4 w-4 text-indigo-400" />
                </div>
                Add New Category
              </CardTitle>
              <CardDescription className="text-zinc-400">
                Create a new category or subcategory
              </CardDescription>
            </CardHeader>
            <CardContent className="pt-6">
              <div className="space-y-4">
                <div className="space-y-2">
                  <label className="text-sm font-medium leading-none text-zinc-300">
                    Category Name
                  </label>
                  <Input
                    value={newCategoryName}
                    onChange={(e) => setNewCategoryName(e.target.value)}
                    placeholder="e.g. Electronics, Clothing..."
                    className="h-10 border-white/10 bg-black/20 focus:bg-black/40 transition-colors text-white placeholder:text-zinc-600"
                  />
                </div>
                <div className="space-y-2">
                  <label className="text-sm font-medium leading-none text-zinc-300">
                    Parent Category
                  </label>
                  <Select
                    value={selectedParentId || "none"}
                    onValueChange={setSelectedParentId}
                  >
                    <SelectTrigger className="h-10 border-white/10 bg-black/20 focus:bg-black/40 transition-colors text-white">
                      <SelectValue placeholder="Select parent category" />
                    </SelectTrigger>
                    <SelectContent className="bg-zinc-900 border-white/10 text-white">
                      <SelectItem value="none" className="focus:bg-zinc-800">No parent (root category)</SelectItem>
                      {categories.map((cat) => (
                        <SelectItem key={cat._id} value={cat._id} className="focus:bg-zinc-800">
                          {cat.name}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
                <Button onClick={handleAddCategory} className="w-full mt-2 bg-indigo-600 hover:bg-indigo-700 text-white border-0" size="lg">
                  <Plus className="h-4 w-4 mr-2" />
                  Add Category
                </Button>
              </div>
            </CardContent>
          </Card>

          {/* Category List Card */}
          <Card className="lg:col-span-3 border-none bg-transparent shadow-none">
            <CardHeader className="pl-0 pt-0 pb-4">
              <CardTitle className="text-lg font-bold text-white">Structure</CardTitle>
              <CardDescription className="text-zinc-400">
                Drag and drop to reorder categories
              </CardDescription>
            </CardHeader>
            <CardContent className="p-0">
              <DndProvider backend={HTML5Backend}>
                <div className="space-y-2 min-h-[300px]">
                  {loading ? (
                    <div className="flex flex-col items-center justify-center py-12 text-muted-foreground animate-pulse">
                      <FolderTree className="h-10 w-10 mb-3 opacity-20" />
                      <p>Loading categories...</p>
                    </div>
                  ) : rootCategories.length === 0 ? (
                    <div className="flex flex-col items-center justify-center py-12 text-muted-foreground border-2 border-dashed border-border/40 rounded-xl bg-muted/20">
                      <FolderTree className="h-10 w-10 mb-3 opacity-20" />
                      <p>No categories yet</p>
                      <p className="text-xs opacity-60 mt-1">Add your first category to get started</p>
                    </div>
                  ) : (
                    <div className="space-y-1">
                      {rootCategories.map(category => (
                        <CategoryItem key={category._id} category={category} />
                      ))}
                    </div>
                  )}
                </div>
              </DndProvider>
            </CardContent>
          </Card>
        </div>

        {/* Delete Confirmation Dialog */}
        <AlertDialog open={!!categoryToDelete} onOpenChange={() => setCategoryToDelete(null)}>
          <AlertDialogContent>
            <AlertDialogHeader>
              <AlertDialogTitle>Are you sure?</AlertDialogTitle>
              <AlertDialogDescription>
                This will permanently delete the category <span className="font-medium text-foreground">"{categoryToDelete?.name}"</span>.
                This action cannot be undone.
              </AlertDialogDescription>
            </AlertDialogHeader>
            <AlertDialogFooter>
              <AlertDialogCancel>Cancel</AlertDialogCancel>
              <AlertDialogAction onClick={handleDeleteConfirm} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
                Delete Category
              </AlertDialogAction>
            </AlertDialogFooter>
          </AlertDialogContent>
        </AlertDialog>
      </div>
    </Layout>
  );
} 

