'use client';

import React, { useState, useMemo, useEffect, ComponentType, useCallback } from 'react';
import * as Accordion from '@radix-ui/react-accordion';
import {
    Search, PlusSquare, ChevronDown, GripVertical,
    Package, Plus,
} from 'lucide-react';
import { type Node as FlowNode } from '@xyflow/react';
import { getNodeId } from '@/utils/react-flow';
import { RegisteredNode, NodeCategory } from '@/components/core/designer/nodes/types';

import { useNodesStore } from '@/stores/nodes-store';
import { useFlowStoreActions } from '@/stores/flow-store';
import { useSidebarStore } from '@/stores/sidebar-store';
interface NodeListItemData {
    label: string;
    version: string;
    name: string;
    summary: string;
    mode: string;
}

interface NodeListItem {
    name: string;
    NodeIconComponent: ComponentType<any>;
    nodeIconColor: string;
    nodeType: string;
    data: NodeListItemData;
    id: string;
}

interface NodeGroup {
    type: string;
    CategoryIconComponent: ComponentType<any>;
    items: NodeListItem[];
}

interface DraggableNodeItemProps {
    item: NodeListItem;
    isHovered: boolean;
    isSelected: boolean;
    onItemDragStart: (event: React.DragEvent<HTMLDivElement>, nodeType: string, label: string, data: NodeListItemData) => void;
    onItemMouseEnter: () => void;
    onItemMouseLeave: () => void;
    onItemAdd: (nodeType: string, label: string, data: NodeListItemData) => void;
    onItemSelect: (nodeType: string, label: string, data: NodeListItemData, iconComponent: any, iconColor: string) => void;
}

const DraggableNodeItem = React.memo<DraggableNodeItemProps>(({ 
    item, 
    isHovered,
    isSelected, 
    onItemDragStart, 
    onItemMouseEnter, 
    onItemMouseLeave, 
    onItemAdd,
    onItemSelect 
}) => {
    const ItmIcon = item.NodeIconComponent as any;
    return (
        <div
            className={`group/item flex items-center justify-between px-2.5 py-2 rounded-md cursor-pointer relative border transition-all ${
                isSelected 
                    ? 'bg-blue-50 border-blue-300 shadow-sm' 
                    : 'bg-gray-50 border-gray-200 hover:bg-gray-100'
            }`}
            draggable
            onDragStart={(event) => onItemDragStart(event, item.nodeType ?? 'default', item.name, item.data)}
            onMouseEnter={onItemMouseEnter}
            onMouseLeave={onItemMouseLeave}
            onClick={() => onItemSelect(item.nodeType ?? 'default', item.name, item.data, item.NodeIconComponent, item.nodeIconColor)}
        >
            <div className="flex items-center space-x-2 flex-grow min-w-0">
                <ItmIcon size={16} className={`text-${item.nodeIconColor}-600 flex-shrink-0`} />
                <span className="text-xs font-medium text-gray-700 truncate">{item.name}</span>
            </div>
            <div className="flex items-center space-x-1">
                <button
                    onClick={(e) => {
                        e.stopPropagation();
                        onItemAdd(item.nodeType, item.name, item.data);
                    }}
                    className={`p-1 hover:bg-gray-200 rounded text-gray-500 hover:text-blue-500 transition-all ${
                        isHovered ? 'opacity-100' : 'opacity-0'
                    }`}
                    title={`Add ${item.name}`}
                >
                    <Plus size={12} />
                </button>
                <GripVertical size={14} className="text-gray-400 hover:text-gray-600 flex-shrink-0" />
            </div>
        </div>
    );
});
DraggableNodeItem.displayName = 'DraggableNodeItem';

const NodeList = () => {
    const [searchTerm, setSearchTerm] = useState('');
    const [openAccordionItems, setOpenAccordionItems] = useState<string[]>([]);
    const [hoveredItemId, setHoveredItemId] = useState<string | null>(null);

    const { addNode } = useFlowStoreActions();
    const { selectedComponent, setSelectedComponent } = useSidebarStore();

    const onDragStart = useCallback((event: React.DragEvent<HTMLDivElement>, nodeType: string, label: string, data: NodeListItemData) => {
        event.dataTransfer.setData('application/reactflow', JSON.stringify({ nodeType, label, data }));
        event.dataTransfer.effectAllowed = 'move';
    }, []);

    const { nodes, nodeCategories } = useNodesStore();

    const handleAddNode = useCallback((nodeType: string, label: string, itemData: NodeListItemData) => {
        const position = { x: Math.random() * 400, y: Math.random() * 400 };
        const newNode: FlowNode = {
            id: getNodeId(nodeType),
            type: nodeType,
            position,
            data: { ...itemData, label },
        };
        addNode(newNode);
    }, [addNode]);

    const componentGroups = useMemo((): NodeGroup[] => {
        if (!nodeCategories || !nodes || !Array.isArray(nodeCategories) || !Array.isArray(nodes)) {
            return [];
        }
        return nodeCategories.map((category: NodeCategory) => {
            const categoryItems: NodeListItem[] = (nodes || [])
                .filter((node: RegisteredNode) => node && node.category === category.type)
                .map((node: RegisteredNode, index: number) => {
                    const name = node.type.charAt(0).toUpperCase() + node.type.slice(1);
                    const IconComp = node.configuration.icon ?? Package;
                    const iconColor = node.configuration.color ?? 'gray';
                    return {
                        name,
                        NodeIconComponent: IconComp,
                        nodeIconColor: iconColor,
                        nodeType: node.type,
                        id: `${category.type}-${node.type}-${index}`,
                        data: {
                            ...node.configuration.defaultData,
                            ...(node?.configuration?.editor ? { editor: node.configuration.editor } : {}),
                        }
                    };
                });

            return {
                type: category.label,
                CategoryIconComponent: category.icon,
                items: categoryItems,
            };
        });
    }, [nodes, nodeCategories]);

    const filteredAndMemoizedGroups = useMemo(() => {
        if (!componentGroups || !Array.isArray(componentGroups) || componentGroups.length === 0) return [];
        return componentGroups
            .map((group: NodeGroup | null) => {
                if (!group || !group.items || !Array.isArray(group.items)) return null;
                if (group.type.toLowerCase().includes(searchTerm.toLowerCase())) {
                    return group;
                }
                const filteredItems = group.items.filter((item: NodeListItem) =>
                    item && item.name && item.name.toLowerCase().includes(searchTerm.toLowerCase())
                );
                if (filteredItems.length > 0) {
                    return { ...group, items: filteredItems };
                }
                return null;
            })
            .filter((group): group is NodeGroup => group !== null);
    }, [searchTerm, componentGroups]);

    useEffect(() => {
        if (searchTerm.trim() === '') {
            // Open all sections by default
            const allSections = filteredAndMemoizedGroups.map((g: NodeGroup) => g.type);
            if (JSON.stringify(openAccordionItems) !== JSON.stringify(allSections)) {
                setOpenAccordionItems(allSections);
            }
        } else {
            const itemsToOpen = filteredAndMemoizedGroups.map((g: NodeGroup) => g.type);
            if (JSON.stringify(openAccordionItems) !== JSON.stringify(itemsToOpen)) {
                setOpenAccordionItems(itemsToOpen);
            }
        }
    }, [searchTerm, filteredAndMemoizedGroups]);

    const handleItemMouseEnter = useCallback((itemId: string) => {
        setHoveredItemId(itemId);
    }, []);

    const handleItemMouseLeave = useCallback(() => {
        setHoveredItemId(null);
    }, []);

    const handleItemSelect = useCallback((nodeType: string, label: string, data: NodeListItemData, iconComponent: any, iconColor: string) => {
        const component = {
            nodeType,
            label,
            data,
            iconComponent,
            iconColor
        };
        // Toggle selection - if same component is clicked, deselect
        if (selectedComponent && selectedComponent.nodeType === nodeType && selectedComponent.label === label) {
            setSelectedComponent(null);
        } else {
            setSelectedComponent(component);
        }
    }, [selectedComponent, setSelectedComponent]);

    return (
        <div className="bg-white text-gray-800 w-full h-full flex flex-col">
            <div className="px-3 py-2 border-b border-gray-200">
                <div className="relative">
                    <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400" size={14} />
                    <input
                        type="text"
                        placeholder="Search nodes"
                        className="pl-8 pr-3 py-1.5 w-full border border-gray-300 rounded text-xs bg-gray-50 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500"
                        onChange={(e) => setSearchTerm(e.target.value)}
                        value={searchTerm}
                    />
                </div>
            </div>
            <Accordion.Root
                type="multiple"
                value={openAccordionItems}
                onValueChange={setOpenAccordionItems}
                className="flex-grow overflow-y-auto px-3 pb-3 space-y-1"
            >
                {filteredAndMemoizedGroups.length === 0 && searchTerm.trim() !== '' ? (
                    <p className="p-4 text-center text-gray-500">No results found.</p>
                ) : (
                    filteredAndMemoizedGroups
                        .map((group: NodeGroup) => {
                            const GrpIcon = group.CategoryIconComponent as any;
                            return group && (
                                <Accordion.Item key={group.type} value={group.type} className="border-0">
                                    <Accordion.Header>
                                        <Accordion.Trigger className="flex items-center w-full py-4 pb-2 text-left group text-xs font-medium text-gray-900 focus:outline-none">
                                            <span className="flex-1">{group.type}</span>
                                            <ChevronDown
                                                className="h-4 w-4 text-gray-500 transition-transform duration-200 group-data-[state=open]:rotate-180"
                                                aria-hidden
                                            />
                                        </Accordion.Trigger>
                                    </Accordion.Header>
                                    <Accordion.Content className="overflow-hidden text-sm transition-all data-[state=open]:animate-accordion-down data-[state=closed]:animate-accordion-up">
                                        <div className="pt-1 pb-2 space-y-1.5">
                                            {group.items.map((item: NodeListItem) => (
                                                <DraggableNodeItem
                                                    key={item.id}
                                                    item={item}
                                                    isHovered={hoveredItemId === item.id}
                                                    isSelected={selectedComponent?.nodeType === item.nodeType && selectedComponent?.label === item.name}
                                                    onItemDragStart={onDragStart}
                                                    onItemMouseEnter={() => handleItemMouseEnter(item.id)}
                                                    onItemMouseLeave={handleItemMouseLeave}
                                                    onItemAdd={handleAddNode}
                                                    onItemSelect={handleItemSelect}
                                                />
                                            ))}
                                        </div>
                                    </Accordion.Content>
                                </Accordion.Item>
                            );
                        })
                )}
            </Accordion.Root>
        </div>
    );
};

export default NodeList;