'use client';


import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
import { WorkflowData, PlotNode, PlotConnection, PlotNodeType, Entity, EntityType } from '@/lib/types';
import { Plus, Trash2, ArrowRight, BookOpen, MessageCircle, Zap, Palette, Save, Link2 } from 'lucide-react';

interface StoryWorkflowProps {
    data: WorkflowData;
    onUpdate: (data: WorkflowData) => void;
    entities: Entity[];
    onNavigateToEntity: (entityId: string) => void;
}

const CARD_WIDTH = 260;
const CARD_HEIGHT = 220;

const INITIAL_COLORS = [
    '#ffffff', // White
    '#dbeafe', // Blue
    '#dcfce7', // Green
    '#fef9c3', // Yellow
    '#fee2e2', // Red
    '#f3e8ff', // Purple
];

const renderTextWithLinks = (text: string, entities: Entity[], onNavigate: (id: string) => void) => {
    if (!text) return <span className="text-slate-400 italic">Description...</span>;

    const parts: (string | React.ReactNode)[] = [text];

    entities.forEach(entity => {
        if (!entity.name) return;
        const regex = new RegExp(`(${entity.name})`, 'gi');

        for (let i = 0; i < parts.length; i++) {
            const part = parts[i];
            if (typeof part === 'string') {
                const split = part.split(regex);
                if (split.length > 1) {
                    const newParts = split.map((s, idx) => {
                        if (s.toLowerCase() === entity.name.toLowerCase()) {
                            return (
                                <span
                                    key={`${entity.id}-${idx}`}
                                    onClick={(e) => { e.stopPropagation(); onNavigate(entity.id); }}
                                    className="text-indigo-600 hover:text-indigo-800 underline decoration-indigo-300 hover:decoration-indigo-600 cursor-pointer font-medium bg-indigo-50 px-0.5 rounded transition-all"
                                    title={`Voir la fiche de ${entity.name}`}
                                >
                                    {s}
                                </span>
                            );
                        }
                        return s;
                    });
                    parts.splice(i, 1, ...newParts);
                    i += newParts.length - 1;
                }
            }
        }
    });

    return <>{parts}</>;
};

interface StoryNodeProps {
    node: PlotNode;
    isSelected: boolean;
    isEditing: boolean;
    isDragging: boolean;
    activeColorPickerId: string | null;
    entities: Entity[];
    savedColors: string[];

    onMouseDown: (e: React.MouseEvent, id: string) => void;
    onMouseUp: (e: React.MouseEvent, id: string) => void;
    onStartConnection: (e: React.MouseEvent, id: string) => void;
    onUpdate: (id: string, updates: Partial<PlotNode>) => void;
    onSetEditing: (id: string | null) => void;
    onToggleColorPicker: (id: string) => void;
    onSaveColor: (color: string) => void;
    onNavigateToEntity: (id: string) => void;

    onInputFocus: (e: React.FocusEvent) => void;
    onInputCheckAutocomplete: (e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>, id: string, field: 'title' | 'description') => void;
    onKeyDownInInput: (e: React.KeyboardEvent, id: string) => void;
}

const StoryNode = React.memo(({
    node, isSelected, isEditing, isDragging, activeColorPickerId, entities, savedColors,
    onMouseDown, onMouseUp, onStartConnection, onUpdate, onSetEditing,
    onToggleColorPicker, onSaveColor, onNavigateToEntity,
    onInputFocus, onInputCheckAutocomplete, onKeyDownInInput
}: StoryNodeProps) => {

    const [showTypePicker, setShowTypePicker] = useState(false);

    const richDescription = useMemo(() => {
        return renderTextWithLinks(node.description, entities, onNavigateToEntity);
    }, [node.description, entities, onNavigateToEntity]);

    return (
        <div
            className={`absolute flex flex-col rounded-xl shadow-sm border z-10 group
                ${isDragging ? '' : 'transition-all'}
                ${isSelected ? 'ring-2 ring-indigo-500 shadow-lg scale-[1.01]' : 'border-slate-200 hover:shadow-md'}
            `}
            style={{
                transform: `translate3d(${node.x}px, ${node.y}px, 0)`,
                width: CARD_WIDTH,
                height: CARD_HEIGHT,
                backgroundColor: node.color || '#ffffff',
                willChange: 'transform'
            }}
            onMouseDown={(e) => onMouseDown(e, node.id)}
            onMouseUp={(e) => onMouseUp(e, node.id)}
            onDoubleClick={(e) => e.stopPropagation()}
            onMouseLeave={() => setShowTypePicker(false)}
        >
            <div className="h-1.5 rounded-t-xl bg-black/5 w-full cursor-grab active:cursor-grabbing" />

            <div className="flex-1 px-4 pb-4 pt-2 flex flex-col overflow-hidden relative">
                <div className="flex justify-between items-start mb-2 relative">
                    {isEditing ? (
                        <input
                            className="font-bold text-slate-800 bg-white/50 border-b border-indigo-400 outline-none w-full mr-6 text-sm p-1 rounded"
                            value={node.title}
                            onChange={(e) => onUpdate(node.id, { title: e.target.value })}
                            onFocus={onInputFocus}
                            autoFocus
                        />
                    ) : (
                        <div
                            className="font-bold text-slate-800 cursor-text truncate mr-6 text-sm"
                            onDoubleClick={() => onSetEditing(node.id)}
                        >
                            {node.title}
                        </div>
                    )}

                    <button
                        onClick={(e) => { e.stopPropagation(); onToggleColorPicker(node.id); }}
                        className="p-1 rounded-full hover:bg-black/10 text-slate-400 hover:text-indigo-600 transition-colors absolute right-0 top-0"
                    >
                        <Palette size={14} />
                    </button>

                    {activeColorPickerId === node.id && (
                        <div className="absolute right-[-10px] top-8 bg-white rounded-lg shadow-xl border border-slate-200 p-3 z-50 w-48 animate-in fade-in zoom-in-95 duration-100 cursor-default" onMouseDown={(e) => e.stopPropagation()}>
                            <div className="grid grid-cols-4 gap-2 mb-3">
                                {savedColors.map(color => (
                                    <button
                                        key={color}
                                        onClick={() => onUpdate(node.id, { color })}
                                        className={`w-8 h-8 rounded-full border border-slate-200 shadow-sm transition-transform hover:scale-110 ${node.color === color ? 'ring-2 ring-offset-1 ring-indigo-400' : ''}`}
                                        style={{ backgroundColor: color }}
                                    />
                                ))}
                            </div>
                            <div className="flex items-center gap-2 pt-2 border-t border-slate-100">
                                <div className="relative w-8 h-8 rounded-full overflow-hidden border border-slate-300 shadow-inner">
                                    <input
                                        type="color"
                                        className="absolute -top-2 -left-2 w-16 h-16 cursor-pointer"
                                        value={node.color || '#ffffff'}
                                        onChange={(e) => onUpdate(node.id, { color: e.target.value })}
                                    />
                                </div>
                                <button
                                    onClick={() => onSaveColor(node.color || '#ffffff')}
                                    className="text-[10px] font-bold text-indigo-600 hover:text-indigo-800 hover:underline flex-1 text-right"
                                >
                                    + SAUVER
                                </button>
                            </div>
                        </div>
                    )}
                </div>

                <div className="flex-1 overflow-y-auto custom-scrollbar relative mb-4">
                    {isEditing ? (
                        <textarea
                            className={`w-full h-full bg-white/70 resize-none outline-none text-xs leading-relaxed p-2 rounded border border-indigo-100 shadow-inner ${node.type === 'dialogue' ? 'font-mono text-slate-700' : 'text-slate-600'}`}
                            placeholder={node.type === 'dialogue' ? "Héros: Salut !\nGuide: ..." : "Résumé de l'intrigue..."}
                            value={node.description}
                            onChange={(e) => onInputCheckAutocomplete(e, node.id, 'description')}
                            onKeyDown={(e) => onKeyDownInInput(e, node.id)}
                            onFocus={onInputFocus}
                            onBlur={() => onSetEditing(null)}
                        />
                    ) : (
                        <div
                            className={`w-full h-full text-xs text-slate-600 leading-relaxed p-1 cursor-text whitespace-pre-wrap ${node.type === 'dialogue' ? 'font-mono bg-indigo-50/30 rounded pl-2 border-l-2 border-indigo-200' : ''}`}
                            onClick={() => onSetEditing(node.id)}
                        >
                            {richDescription}
                        </div>
                    )}
                </div>

                <div className="absolute bottom-2 right-2 z-20">
                    {showTypePicker && (
                        <div className="absolute bottom-full mb-2 right-0 bg-white shadow-xl border border-slate-200 rounded-lg p-1 flex gap-1 animate-in zoom-in-95 duration-100 w-max" onMouseDown={(e) => e.stopPropagation()}>
                            <button
                                onClick={(e) => { e.stopPropagation(); onUpdate(node.id, { type: 'story' }); setShowTypePicker(false); }}
                                className={`p-1.5 rounded hover:bg-slate-100 ${node.type === 'story' ? 'bg-indigo-50 ring-1 ring-indigo-200' : ''}`}
                                title="Narration"
                            >
                                <BookOpen size={14} className="text-slate-500" />
                            </button>
                            <button
                                onClick={(e) => { e.stopPropagation(); onUpdate(node.id, { type: 'action' }); setShowTypePicker(false); }}
                                className={`p-1.5 rounded hover:bg-amber-50 ${node.type === 'action' ? 'bg-amber-50 ring-1 ring-amber-200' : ''}`}
                                title="Action"
                            >
                                <Zap size={14} className="text-amber-500" />
                            </button>
                            <button
                                onClick={(e) => { e.stopPropagation(); onUpdate(node.id, { type: 'dialogue' }); setShowTypePicker(false); }}
                                className={`p-1.5 rounded hover:bg-blue-50 ${node.type === 'dialogue' ? 'bg-blue-50 ring-1 ring-blue-200' : ''}`}
                                title="Dialogue"
                            >
                                <MessageCircle size={14} className="text-blue-500" />
                            </button>
                        </div>
                    )}

                    <button
                        className="p-1.5 rounded-full bg-white/70 hover:bg-white shadow-sm border border-slate-100 hover:border-indigo-200 transition-all opacity-80 group-hover:opacity-100"
                        onClick={(e) => { e.stopPropagation(); setShowTypePicker(!showTypePicker); }}
                    >
                        {node.type === 'story' && <BookOpen size={14} className="text-slate-500" />}
                        {node.type === 'action' && <Zap size={14} className="text-amber-500" />}
                        {node.type === 'dialogue' && <MessageCircle size={14} className="text-blue-500" />}
                    </button>
                </div>
            </div>

            <button
                className="absolute -right-3 top-1/2 -translate-y-1/2 w-6 h-6 bg-white border border-slate-300 rounded-full flex items-center justify-center text-slate-400 hover:text-indigo-600 hover:border-indigo-500 shadow-sm opacity-0 group-hover:opacity-100 transition-all z-20"
                onMouseDown={(e) => onStartConnection(e, node.id)}
            >
                <ArrowRight size={12} />
            </button>
        </div>
    );
}, (prev, next) => {
    return (
        prev.node === next.node &&
        prev.isSelected === next.isSelected &&
        prev.isEditing === next.isEditing &&
        prev.isDragging === next.isDragging &&
        prev.activeColorPickerId === next.activeColorPickerId &&
        prev.entities === next.entities
    );
});

interface SuggestionState {
    active: boolean;
    trigger: string;
    query: string;
    nodeId: string;
    field: 'title' | 'description';
    cursorIndex: number;
    selectedIndex: number;
    filteredEntities: Entity[];
}

const StoryWorkflow: React.FC<StoryWorkflowProps> = ({ data, onUpdate, entities, onNavigateToEntity }) => {
    const containerRef = useRef<HTMLDivElement>(null);
    const rafRef = useRef<number | null>(null);

    const [internalNodes, setInternalNodes] = useState<PlotNode[]>(data.nodes);
    const internalNodesRef = useRef(internalNodes);
    useEffect(() => { internalNodesRef.current = internalNodes; }, [internalNodes]);

    useEffect(() => {
        setInternalNodes(data.nodes);
    }, [data.nodes]);

    useEffect(() => {
        return () => {
            if (rafRef.current) cancelAnimationFrame(rafRef.current);
        };
    }, []);

    const [activeSuggestion, setActiveSuggestion] = useState<SuggestionState | null>(null);
    const [selectedNodeIds, setSelectedNodeIds] = useState<Set<string>>(new Set());
    const [savedColors, setSavedColors] = useState<string[]>(INITIAL_COLORS);
    const [activeColorPickerId, setActiveColorPickerId] = useState<string | null>(null);
    const [editingNodeId, setEditingNodeId] = useState<string | null>(null);
    const [history, setHistory] = useState<WorkflowData[]>([]);

    const [isDragging, setIsDragging] = useState(false);
    const [dragStartPositions, setDragStartPositions] = useState<Map<string, { x: number, y: number }>>(new Map());
    const [dragStartMouse, setDragStartMouse] = useState({ x: 0, y: 0 });

    const [connectingNodeId, setConnectingNodeId] = useState<string | null>(null);
    const [mousePos, setMousePos] = useState({ x: 0, y: 0 });

    const [isPanning, setIsPanning] = useState(false);
    const [panStart, setPanStart] = useState({ x: 0, y: 0 });
    const [scrollStart, setScrollStart] = useState({ x: 0, y: 0 });

    const pushHistory = useCallback(() => {
        setHistory(prev => {
            const newHistory = [...prev, data];
            if (newHistory.length > 20) return newHistory.slice(newHistory.length - 20);
            return newHistory;
        });
    }, [data]);

    const updateNode = useCallback((id: string, updates: Partial<PlotNode>) => {
        const currentNodes = internalNodesRef.current;
        onUpdate({
            ...data,
            nodes: currentNodes.map(n => n.id === id ? { ...n, ...updates } : n)
        });
    }, [data, onUpdate]);

    const handleInputFocus = useCallback((e: React.FocusEvent) => {
        e.stopPropagation();
    }, []);

    const handleInputWithAutocomplete = useCallback((
        e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>,
        nodeId: string,
        field: 'title' | 'description'
    ) => {
        const val = e.target.value;
        updateNode(nodeId, { [field]: val });

        const cursor = e.target.selectionStart || 0;
        const textBeforeCursor = val.slice(0, cursor);
        const match = textBeforeCursor.match(/([@#^])([^@#^\s]*)$/);

        if (match) {
            const trigger = match[1];
            const query = match[2].toLowerCase();
            const targetType = trigger === '@' ? EntityType.CHARACTER : trigger === '#' ? EntityType.LOCATION : EntityType.OBJECT;
            const filtered = entities.filter(ent =>
                ent.type === targetType &&
                ent.name.toLowerCase().includes(query)
            );

            setActiveSuggestion({
                active: true,
                trigger,
                query,
                nodeId,
                field,
                cursorIndex: cursor,
                selectedIndex: 0,
                filteredEntities: filtered
            });
        } else {
            setActiveSuggestion(null);
        }
    }, [updateNode, entities]);

    const insertEntity = (entity: Entity) => {
        if (!activeSuggestion) return;
        const { nodeId, field, trigger, query } = activeSuggestion;
        const node = internalNodesRef.current.find(n => n.id === nodeId);
        if (!node) return;
        const currentText = node[field] as string;
        const cursor = activeSuggestion.cursorIndex;
        const insertionLength = trigger.length + query.length;
        const startIdx = cursor - insertionLength;
        if (startIdx < 0) return;
        const before = currentText.slice(0, startIdx);
        const after = currentText.slice(cursor);
        const isDialogue = node.type === 'dialogue' && activeSuggestion.trigger === '@';
        const suffix = isDialogue ? ": " : " ";
        updateNode(nodeId, { [field]: before + entity.name + suffix + after });
        setActiveSuggestion(null);
    };

    const handleKeyDownInInput = useCallback((e: React.KeyboardEvent, nodeId: string) => {
        if (activeSuggestion && activeSuggestion.nodeId === nodeId) {
            if (e.key === 'ArrowDown') {
                e.preventDefault();
                setActiveSuggestion(prev => prev ? { ...prev, selectedIndex: (prev.selectedIndex + 1) % prev.filteredEntities.length } : null);
                return;
            } else if (e.key === 'ArrowUp') {
                e.preventDefault();
                setActiveSuggestion(prev => prev ? { ...prev, selectedIndex: (prev.selectedIndex - 1 + prev.filteredEntities.length) % prev.filteredEntities.length } : null);
                return;
            } else if (e.key === 'Tab' || e.key === 'Enter') {
                e.preventDefault();
                if (activeSuggestion.filteredEntities.length > 0) {
                    insertEntity(activeSuggestion.filteredEntities[activeSuggestion.selectedIndex]);
                } else {
                    setActiveSuggestion(null);
                }
                return;
            } else if (e.key === 'Escape') {
                setActiveSuggestion(null);
                return;
            }
        }
    }, [activeSuggestion, entities, updateNode]);

    const handleNodeMouseDown = useCallback((e: React.MouseEvent, nodeId: string) => {
        e.stopPropagation();
        setActiveColorPickerId(null);

        setSelectedNodeIds(prevSelected => {
            const newSelection = new Set(prevSelected);
            if (e.ctrlKey) {
                if (newSelection.has(nodeId)) newSelection.delete(nodeId);
                else newSelection.add(nodeId);
            } else {
                if (!newSelection.has(nodeId)) {
                    newSelection.clear();
                    newSelection.add(nodeId);
                }
            }
            const finalDragIds = e.ctrlKey ? newSelection : (newSelection.has(nodeId) ? newSelection : new Set([nodeId]));
            const startPositions = new Map<string, { x: number, y: number }>();
            internalNodesRef.current.forEach(n => {
                if (finalDragIds.has(n.id)) {
                    startPositions.set(n.id, { x: n.x, y: n.y });
                }
            });
            setDragStartPositions(startPositions);
            return newSelection;
        });

        setIsDragging(true);
        setDragStartMouse({ x: e.clientX, y: e.clientY });
        pushHistory();
    }, [pushHistory]);

    const startConnection = useCallback((e: React.MouseEvent, nodeId: string) => {
        e.stopPropagation();
        pushHistory();
        setConnectingNodeId(nodeId);
    }, [pushHistory]);

    const finishConnection = useCallback((e: React.MouseEvent, targetId: string) => {
        if (connectingNodeId && connectingNodeId !== targetId) {
            const exists = data.connections.some(c => c.source === connectingNodeId && c.target === targetId);
            if (!exists) {
                const newConn: PlotConnection = {
                    id: `conn-${Date.now()}`,
                    source: connectingNodeId,
                    target: targetId
                };
                onUpdate({
                    ...data,
                    nodes: internalNodesRef.current,
                    connections: [...data.connections, newConn]
                });
            }
        }
        setConnectingNodeId(null);
    }, [data, onUpdate, connectingNodeId]);

    const handleToggleColorPicker = useCallback((id: string) => {
        setActiveColorPickerId(prev => prev === id ? null : id);
    }, []);

    const handleSaveColor = useCallback((color: string) => {
        setSavedColors(prev => !prev.includes(color) ? [...prev, color] : prev);
    }, []);

    const handleMouseMove = (e: React.MouseEvent) => {
        const rect = containerRef.current?.getBoundingClientRect();
        if (!rect) return;
        const clientX = e.clientX;
        const clientY = e.clientY;

        if (isPanning && containerRef.current) {
            const dx = clientX - panStart.x;
            const dy = clientY - panStart.y;
            containerRef.current.scrollLeft = scrollStart.x - dx;
            containerRef.current.scrollTop = scrollStart.y - dy;
            return;
        }

        // Only update mousePos when connecting (drawing a line), not during node drag
        if (connectingNodeId) {
            const scrollLeft = containerRef.current?.scrollLeft || 0;
            const scrollTop = containerRef.current?.scrollTop || 0;
            setMousePos({ x: clientX - rect.left + scrollLeft, y: clientY - rect.top + scrollTop });
        }

        if (isDragging) {
            if (rafRef.current) return;
            rafRef.current = requestAnimationFrame(() => {
                const dx = clientX - dragStartMouse.x;
                const dy = clientY - dragStartMouse.y;
                setInternalNodes(prevNodes => prevNodes.map(node => {
                    const startPos = dragStartPositions.get(node.id);
                    if (startPos) return { ...node, x: startPos.x + dx, y: startPos.y + dy };
                    return node;
                }));
                rafRef.current = null;
            });
        }
    };

    const handleMouseUp = (e: React.MouseEvent) => {
        if (rafRef.current) {
            cancelAnimationFrame(rafRef.current);
            rafRef.current = null;
        }
        if (isDragging) onUpdate({ ...data, nodes: internalNodesRef.current });

        // Hit-test: if connecting, check if mouse is over any node
        if (connectingNodeId && containerRef.current) {
            const rect = containerRef.current.getBoundingClientRect();
            const scrollLeft = containerRef.current.scrollLeft;
            const scrollTop = containerRef.current.scrollTop;
            const mx = e.clientX - rect.left + scrollLeft;
            const my = e.clientY - rect.top + scrollTop;

            const targetNode = internalNodesRef.current.find(n =>
                n.id !== connectingNodeId &&
                mx >= n.x && mx <= n.x + CARD_WIDTH &&
                my >= n.y && my <= n.y + CARD_HEIGHT
            );

            if (targetNode) {
                const exists = data.connections.some(
                    c => c.source === connectingNodeId && c.target === targetNode.id
                );
                if (!exists) {
                    const newConn: PlotConnection = {
                        id: `conn-${Date.now()}`,
                        source: connectingNodeId,
                        target: targetNode.id,
                    };
                    onUpdate({
                        ...data,
                        nodes: internalNodesRef.current,
                        connections: [...data.connections, newConn],
                    });
                }
            }
        }

        setIsDragging(false);
        setIsPanning(false);
        setConnectingNodeId(null);
    };

    const handleCanvasMouseDown = (e: React.MouseEvent) => {
        if (!e.ctrlKey) setSelectedNodeIds(new Set());
        setActiveSuggestion(null);
        setActiveColorPickerId(null);
        setEditingNodeId(null);
        setIsPanning(true);
        setPanStart({ x: e.clientX, y: e.clientY });
        if (containerRef.current) {
            setScrollStart({ x: containerRef.current.scrollLeft, y: containerRef.current.scrollTop });
        }
    };

    const handleCanvasDoubleClick = (e: React.MouseEvent) => {
        e.preventDefault();
        const rect = containerRef.current?.getBoundingClientRect();
        if (!rect) return;
        const x = e.clientX - rect.left + (containerRef.current?.scrollLeft || 0) - CARD_WIDTH / 2;
        const y = e.clientY - rect.top + (containerRef.current?.scrollTop || 0) - CARD_HEIGHT / 2;
        pushHistory();
        const newNode: PlotNode = {
            id: `node-${Date.now()}`,
            x,
            y,
            title: 'Nouvel événement',
            description: '',
            color: INITIAL_COLORS[0],
            type: 'story'
        };
        onUpdate({ ...data, nodes: [...internalNodesRef.current, newNode] });
        setSelectedNodeIds(new Set([newNode.id]));
        setEditingNodeId(newNode.id);
    };

    const handleDeleteSelected = () => {
        if (selectedNodeIds.size === 0) return;
        pushHistory();
        const newNodes = internalNodes.filter(n => !selectedNodeIds.has(n.id));
        const newConnections = data.connections.filter(c => !selectedNodeIds.has(c.source) && !selectedNodeIds.has(c.target));
        onUpdate({ nodes: newNodes, connections: newConnections });
        setSelectedNodeIds(new Set());
    };

    const handleAddNodeCenter = () => {
        pushHistory();
        const scrollLeft = containerRef.current?.scrollLeft || 0;
        const scrollTop = containerRef.current?.scrollTop || 0;
        const clientWidth = containerRef.current?.clientWidth || 800;
        const clientHeight = containerRef.current?.clientHeight || 600;
        const newNode: PlotNode = {
            id: `node-${Date.now()}`,
            x: scrollLeft + clientWidth / 2 - CARD_WIDTH / 2,
            y: scrollTop + clientHeight / 2 - CARD_HEIGHT / 2,
            title: 'Nouveau point d\'intrigue',
            description: '',
            color: INITIAL_COLORS[0],
            type: 'story'
        };
        onUpdate({ ...data, nodes: [...internalNodesRef.current, newNode] });
        setSelectedNodeIds(new Set([newNode.id]));
        setEditingNodeId(newNode.id);
    };

    return (
        <div className="h-full flex flex-col overflow-hidden bg-theme-bg relative transition-colors duration-300">
            <div className="h-12 bg-theme-panel border-b border-theme-border flex items-center justify-between px-4 z-10 shadow-sm shrink-0 transition-colors duration-300">
                <div className="flex items-center gap-2">
                    <button onClick={handleAddNodeCenter} className="flex items-center gap-1.5 px-3 py-1.5 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 text-xs font-bold transition-all shadow-md shadow-indigo-100">
                        <Plus size={14} /> AJOUTER NŒUD
                    </button>
                    <div className="w-px h-6 bg-theme-border mx-2" />
                    <div className="text-[10px] uppercase font-bold text-theme-muted tracking-wider">
                        {selectedNodeIds.size > 0 ? `${selectedNodeIds.size} SÉLECTIONNÉ(S)` : 'Double-cliquez sur le canvas pour créer'}
                    </div>
                </div>
                <div className="flex items-center gap-2">
                    <button onClick={handleDeleteSelected} disabled={selectedNodeIds.size === 0} className="p-2 text-red-500 hover:bg-red-500/10 rounded-lg disabled:opacity-30 transition-colors" title="Supprimer">
                        <Trash2 size={16} />
                    </button>
                </div>
            </div>

            <div
                ref={containerRef}
                className="flex-1 overflow-auto relative cursor-grab active:cursor-grabbing bg-theme-bg canvas-grid transition-colors duration-300"
                onMouseDown={handleCanvasMouseDown}
                onMouseMove={handleMouseMove}
                onMouseUp={handleMouseUp}
                onDoubleClick={handleCanvasDoubleClick}
                style={{
                    backgroundImage: 'radial-gradient(var(--theme-border) 1px, transparent 1px)',
                    backgroundSize: '24px 24px'
                }}
            >
                <svg className="absolute top-0 left-0 w-[4000px] h-[4000px] pointer-events-none z-0">
                    {data.connections.map(conn => {
                        const source = internalNodes.find(n => n.id === conn.source);
                        const target = internalNodes.find(n => n.id === conn.target);
                        if (!source || !target) return null;
                        const startX = source.x + CARD_WIDTH / 2;
                        const startY = source.y + CARD_HEIGHT / 2;
                        const endX = target.x + CARD_WIDTH / 2;
                        const endY = target.y + CARD_HEIGHT / 2;
                        return (
                            <line key={conn.id} x1={startX} y1={startY} x2={endX} y2={endY} stroke="var(--theme-border)" strokeWidth="2" markerEnd="url(#arrowhead)" />
                        );
                    })}
                    {connectingNodeId && (
                        <line
                            x1={(internalNodes.find(n => n.id === connectingNodeId)?.x || 0) + CARD_WIDTH / 2}
                            y1={(internalNodes.find(n => n.id === connectingNodeId)?.y || 0) + CARD_HEIGHT / 2}
                            x2={mousePos.x} y2={mousePos.y}
                            stroke="#6366f1" strokeWidth="2" strokeDasharray="5,5" markerEnd="url(#arrowhead-blue)"
                        />
                    )}
                    <defs>
                        <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="28" refY="3.5" orient="auto">
                            <path d="M0,0 L0,7 L10,3.5 Z" fill="var(--theme-border)" />
                        </marker>
                        <marker id="arrowhead-blue" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto">
                            <path d="M0,0 L0,7 L10,3.5 Z" fill="#6366f1" />
                        </marker>
                    </defs>
                </svg>

                {internalNodes.map(node => (
                    <StoryNode
                        key={node.id}
                        node={node}
                        isSelected={selectedNodeIds.has(node.id)}
                        isEditing={editingNodeId === node.id}
                        isDragging={isDragging}
                        activeColorPickerId={activeColorPickerId}
                        entities={entities}
                        savedColors={savedColors}
                        onMouseDown={handleNodeMouseDown}
                        onMouseUp={finishConnection}
                        onStartConnection={startConnection}
                        onUpdate={updateNode}
                        onSetEditing={setEditingNodeId}
                        onToggleColorPicker={handleToggleColorPicker}
                        onSaveColor={handleSaveColor}
                        onNavigateToEntity={onNavigateToEntity}
                        onInputFocus={handleInputFocus}
                        onInputCheckAutocomplete={handleInputWithAutocomplete}
                        onKeyDownInInput={handleKeyDownInInput}
                    />
                ))}
            </div>

            {activeSuggestion && (
                <div className="fixed z-50 bg-white rounded-xl shadow-2xl border border-indigo-100 w-64 max-h-48 overflow-y-auto" style={{ left: '50%', top: '50%', transform: 'translate(-50%, -50%)' }}>
                    <div className="px-3 py-2 bg-indigo-600 text-white text-[10px] font-black uppercase tracking-widest">
                        Insérer {activeSuggestion.trigger === '@' ? 'Personnage' : activeSuggestion.trigger === '#' ? 'Lieu' : 'Objet'}
                    </div>
                    <div className="divide-y divide-slate-50">
                        {activeSuggestion.filteredEntities.length > 0 ? (
                            activeSuggestion.filteredEntities.map((ent, idx) => (
                                <button
                                    key={ent.id}
                                    className={`w-full text-left px-4 py-3 text-xs flex items-center gap-3 hover:bg-indigo-50 transition-colors ${idx === activeSuggestion.selectedIndex ? 'bg-indigo-50 text-indigo-700 font-bold' : 'text-slate-700'}`}
                                    onClick={() => insertEntity(ent)}
                                >
                                    {ent.name}
                                </button>
                            ))
                        ) : (
                            <div className="p-4 text-xs text-slate-400 italic text-center">Aucun résultat</div>
                        )}
                    </div>
                </div>
            )}
        </div>
    );
};

export default StoryWorkflow;
