'use client';

import React, { useMemo, useCallback, useState, ComponentType } from 'react';
import * as Accordion from '@radix-ui/react-accordion';
import { ChevronDown, Package, Circle, Search, Trash2, Copy, Edit2, GripVertical } from 'lucide-react';
import { type Node as FlowNode } from '@xyflow/react';
import useFlowStore, { useFlowStoreActions } from '@/stores/flow-store';
import { useNodesStore } from '@/stores/nodes-store';
import { useEditorStore } from '@/stores/editor-store';
import { RegisteredNode } from '@/components/core/designer/nodes/types';

interface NodeWithConfig extends FlowNode {
    iconComponent?: ComponentType<{ size?: number; className?: string }>;
    iconColor?: string;
}

interface NodeGroup {
    type: string;
    items: NodeWithConfig[];
}

const getNodeName = (node: FlowNode): string => {
    // Priority order for finding the node name
    // 1. Direct label
    if (node.data?.label && typeof node.data.label === 'string') {
        return node.data.label;
    }
    
    // 2. Check for nested structures based on node type
    const nodeType = node.type || 'default';
    
    // Common nested patterns: node.data.{nodeType}.name
    if (node.data && typeof node.data === 'object' && node.data[nodeType] && 
        typeof node.data[nodeType] === 'object' && node.data[nodeType].name && 
        typeof node.data[nodeType].name === 'string') {
        return node.data[nodeType].name;
    }
    
    // 3. Check for common nested patterns
    const commonPaths = [
        'service', 'message', 'channel', 'event', 'command', 'query', 'domain'
    ];
    
    for (const path of commonPaths) {
        if (node.data && typeof node.data === 'object' && node.data[path] && 
            typeof node.data[path] === 'object' && node.data[path].name && 
            typeof node.data[path].name === 'string') {
            return node.data[path].name;
        }
    }
    
    // 4. Fallback to direct name property
    if (node.data?.name && typeof node.data.name === 'string') {
        return node.data.name;
    }
    
    // 5. Final fallback
    return `${nodeType} ${node.id.slice(-4)}`;
};

const getIconColorClass = (color: string): string => {
    const colorMap: Record<string, string> = {
        'red': 'text-red-600',
        'blue': 'text-blue-600',
        'green': 'text-green-600',
        'yellow': 'text-yellow-600',
        'purple': 'text-purple-600',
        'pink': 'text-pink-600',
        'indigo': 'text-indigo-600',
        'orange': 'text-orange-600',
        'teal': 'text-teal-600',
        'cyan': 'text-cyan-600',
        'gray': 'text-gray-600',
        'grey': 'text-gray-600'
    };
    
    return colorMap[color] || 'text-gray-600';
};

const ResourceList = () => {
    const { nodes, reactFlowInstance } = useFlowStore();
    const { deleteNode, duplicateNode } = useFlowStoreActions();
    const { nodes: registeredNodes } = useNodesStore();
    const { setSelectedNode } = useEditorStore();
    const [searchTerm, setSearchTerm] = useState('');
    const [hoveredNodeId, setHoveredNodeId] = useState<string | null>(null);

    const handleNodeClick = useCallback((nodeId: string) => {
        if (reactFlowInstance) {
            const node = nodes.find(n => n.id === nodeId);
            if (node) {
                reactFlowInstance.fitView({
                    nodes: [{ id: nodeId }],
                    duration: 800,
                    padding: 0.3,
                });
                
                // Select the node
                reactFlowInstance.setNodes(prevNodes => 
                    prevNodes.map(n => ({
                        ...n,
                        selected: n.id === nodeId
                    }))
                );
            }
        }
    }, [nodes, reactFlowInstance]);

    const handleDeleteNode = useCallback((nodeId: string, event: React.MouseEvent) => {
        event.stopPropagation();
        deleteNode(nodeId);
    }, [deleteNode]);

    const handleDuplicateNode = useCallback((nodeId: string, event: React.MouseEvent) => {
        event.stopPropagation();
        duplicateNode(nodeId);
    }, [duplicateNode]);

    const handleMouseEnter = useCallback((nodeId: string) => {
        setHoveredNodeId(nodeId);
    }, []);

    const handleMouseLeave = useCallback(() => {
        setHoveredNodeId(null);
    }, []);

    const handleEditNode = useCallback((nodeId: string, event: React.MouseEvent) => {
        event.stopPropagation();
        const node = nodes.find(n => n.id === nodeId);
        if (node) {
            setSelectedNode(node);
        }
    }, [nodes, setSelectedNode]);

    const nodeGroups = useMemo((): NodeGroup[] => {
        if (!nodes || !Array.isArray(nodes) || !registeredNodes) {
            return [];
        }

        // Create a lookup map for registered node configurations
        const nodeConfigMap = registeredNodes.reduce((map: Record<string, { icon: ComponentType<any>; color: string }>, registeredNode: RegisteredNode) => {
            map[registeredNode.type] = {
                icon: registeredNode.configuration?.icon || Circle,
                color: registeredNode.configuration?.color || 'gray'
            };
            return map;
        }, {} as Record<string, { icon: ComponentType<any>; color: string }>);

        const groupedNodes = nodes.reduce((groups: { [key: string]: NodeWithConfig[] }, node: FlowNode) => {
            const nodeType = node.type || 'default';
            const config = nodeConfigMap[nodeType] || { icon: Circle, color: 'gray' };
            
            const nodeWithConfig: NodeWithConfig = {
                ...node,
                iconComponent: config.icon,
                iconColor: config.color
            };

            if (!groups[nodeType]) {
                groups[nodeType] = [];
            }
            groups[nodeType].push(nodeWithConfig);
            return groups;
        }, {});

        return Object.entries(groupedNodes).map(([type, items]) => ({
            type: type.charAt(0).toUpperCase() + type.slice(1),
            items: items
        }));
    }, [nodes, registeredNodes]);

    const filteredNodeGroups = useMemo(() => {
        if (!nodeGroups || !Array.isArray(nodeGroups) || nodeGroups.length === 0) return [];
        if (searchTerm.trim() === '') return nodeGroups;

        return nodeGroups
            .map((group: NodeGroup) => {
                // If group type matches search, return entire group
                if (group.type.toLowerCase().includes(searchTerm.toLowerCase())) {
                    return group;
                }

                // Filter items within the group
                const filteredItems = group.items.filter((node: NodeWithConfig) => {
                    const nodeName = getNodeName(node);
                    return nodeName.toLowerCase().includes(searchTerm.toLowerCase()) ||
                           (node.type || '').toLowerCase().includes(searchTerm.toLowerCase());
                });
                
                if (filteredItems.length > 0) {
                    return { ...group, items: filteredItems };
                }
                return null;
            })
            .filter((group): group is NodeGroup => group !== null);
    }, [searchTerm, nodeGroups]);

    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>
            <div className="flex-grow overflow-y-auto px-3 pb-3 space-y-1">
                {nodeGroups.length === 0 ? (
                    <p className="p-4 text-center text-gray-500">No nodes on canvas.</p>
                ) : filteredNodeGroups.length === 0 && searchTerm.trim() !== '' ? (
                    <p className="p-4 text-center text-gray-500">No results found.</p>
                ) : (
                    <Accordion.Root type="multiple" defaultValue={filteredNodeGroups.map(g => g.type)}>
                        {filteredNodeGroups.map((group: NodeGroup) => (
                            <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((node: NodeWithConfig) => {
                                            const NodeIcon = node.iconComponent || Circle;
                                            const iconColor = node.iconColor || 'gray';
                                            const iconClassName = getIconColorClass(iconColor);
                                            const isHovered = hoveredNodeId === node.id;
                                            return (
                                                <div
                                                    key={node.id}
                                                    className={`group/item flex items-center justify-between px-2.5 py-2 rounded-md cursor-pointer relative border transition-all ${
                                                        false 
                                                            ? 'bg-blue-50 border-blue-300 shadow-sm' 
                                                            : 'bg-gray-50 border-gray-200 hover:bg-gray-100'
                                                    }`}
                                                    onClick={() => handleNodeClick(node.id)}
                                                    onMouseEnter={() => handleMouseEnter(node.id)}
                                                    onMouseLeave={handleMouseLeave}
                                                >
                                                    <div className="flex items-center space-x-2 flex-grow min-w-0">
                                                        <NodeIcon size={16} className={`${iconClassName} flex-shrink-0`} />
                                                        <span className="text-xs font-medium text-gray-700 truncate">
                                                            {getNodeName(node)}
                                                        </span>
                                                    </div>
                                                    <div className="flex items-center space-x-1">
                                                        <button
                                                            onClick={(e) => handleEditNode(node.id, e)}
                                                            className={`p-1 hover:bg-gray-200 rounded text-gray-500 hover:text-blue-500 transition-all ${
                                                                isHovered ? 'opacity-100' : 'opacity-0'
                                                            }`}
                                                            title="Edit node"
                                                        >
                                                            <Edit2 size={12} />
                                                        </button>
                                                        <button
                                                            onClick={(e) => handleDuplicateNode(node.id, e)}
                                                            className={`p-1 hover:bg-gray-200 rounded text-gray-500 hover:text-blue-500 transition-all ${
                                                                isHovered ? 'opacity-100' : 'opacity-0'
                                                            }`}
                                                            title="Duplicate node"
                                                        >
                                                            <Copy size={12} />
                                                        </button>
                                                        <button
                                                            onClick={(e) => handleDeleteNode(node.id, e)}
                                                            className={`p-1 hover:bg-gray-200 rounded text-gray-500 hover:text-blue-500 transition-all ${
                                                                isHovered ? 'opacity-100' : 'opacity-0'
                                                            }`}
                                                            title="Delete node"
                                                        >
                                                            <Trash2 size={12} />
                                                        </button>
                                                        <GripVertical size={14} className="text-gray-400 hover:text-gray-600 flex-shrink-0" />
                                                    </div>
                                                </div>
                                            );
                                        })}
                                    </div>
                                </Accordion.Content>
                            </Accordion.Item>
                        ))}
                    </Accordion.Root>
                )}
            </div>
        </div>
    );
};

export default ResourceList;