import { useEffect, useState, useCallback, useRef } from 'react';
import { useReactFlow } from '@xyflow/react';
import { AppNodeType } from '../types/node';
import { Asset, Storyboard } from '@/types';

export const useCanvasHotkeys = ({ 
    undo, 
    redo, 
    saveHistory, 
    save,
    switchNext,
    switchPrev,
    switchCanvas,
    assets = [],
    storyboards = [],
    createGroup,
    selectedNodeIds = []
}: { 
    undo?: () => void; 
    redo?: () => void; 
    saveHistory?: () => void; 
    save?: () => void;
    switchNext?: () => void;
    switchPrev?: () => void;
    switchCanvas?: (id: string, type: 'main' | 'asset' | 'storyboard') => void;
    assets?: Asset[];
    storyboards?: Storyboard[];
    createGroup?: (title?: string) => string | null;
    selectedNodeIds?: string[];
} = {}) => {
    const { getNodes, setNodes, getEdges, setEdges, screenToFlowPosition } = useReactFlow<AppNodeType>();
    const [clipboard, setClipboard] = useState<AppNodeType | null>(null);
    const mousePosRef = useRef({ x: 0, y: 0 });

    // Keep latest values in ref to avoid re-binding event listeners
    const latestValues = useRef({
        assets,
        storyboards,
        switchCanvas,
        switchNext,
        switchPrev,
        save,
        undo,
        redo,
        saveHistory,
        clipboard,
        createGroup,
        selectedNodeIds,
        getNodes,
        getEdges,
        setNodes,
        setEdges,
        screenToFlowPosition
    });

    useEffect(() => {
        latestValues.current = {
            assets,
            storyboards,
            switchCanvas,
            switchNext,
            switchPrev,
            save,
            undo,
            redo,
            saveHistory,
            clipboard,
            createGroup,
            selectedNodeIds,
            getNodes,
            getEdges,
            setNodes,
            setEdges,
            screenToFlowPosition
        };
    }, [assets, storyboards, switchCanvas, switchNext, switchPrev, save, undo, redo, saveHistory, clipboard, createGroup, selectedNodeIds, getNodes, getEdges, setNodes, setEdges, screenToFlowPosition]);

    useEffect(() => {
        const handleMouseMove = (e: MouseEvent) => {
            mousePosRef.current = { x: e.clientX, y: e.clientY };
        };
        window.addEventListener('mousemove', handleMouseMove);
        return () => window.removeEventListener('mousemove', handleMouseMove);
    }, []);

    const pasteNodes = useCallback((position?: { x: number, y: number }) => {
        const { 
            clipboard, 
            screenToFlowPosition, 
            getNodes, 
            setNodes, 
            saveHistory 
        } = latestValues.current;

        if (!clipboard) return;

        // Save state before paste
        saveHistory?.();

        const targetPos = position || mousePosRef.current;
        const mouseFlowPos = screenToFlowPosition(targetPos);
        
        // Center the node on mouse cursor
        const width = clipboard.measured?.width || clipboard.width || 420;
        const height = clipboard.measured?.height || clipboard.height || 300;
        
        const newPosition = {
            x: mouseFlowPos.x - width / 2,
            y: mouseFlowPos.y - height / 2
        };
        
        // Find max zIndex from existing nodes
        const currentNodes = getNodes();
        const maxZIndex = currentNodes.reduce((max, node) => {
            return Math.max(max, node.zIndex ?? 0);
        }, 0);

        let newNode: AppNodeType;

        if (clipboard.type === 'appNode') {
             newNode = {
                ...clipboard,
                id: `appNode-${Date.now()}`,
                position: newPosition,
                zIndex: maxZIndex + 1, // Set pasted node to top layer
                selected: true,
                parentId: undefined,
                data: {
                    ...clipboard.data,
                    title: clipboard.data.title ? `${clipboard.data.title} (Copy)` : 'Copy'
                }
            };
        } else if (clipboard.type === 'group') {
             newNode = {
                ...clipboard,
                id: `group-${Date.now()}`,
                position: newPosition,
                zIndex: maxZIndex + 1, // Set pasted node to top layer
                selected: true,
                parentId: undefined,
                data: {
                    ...clipboard.data,
                    label: clipboard.data.label ? `${clipboard.data.label} (Copy)` : 'Group Copy'
                }
            };
        } else {
            return;
        }

        // Deselect other nodes and add new one
        setNodes((nodes) => [...nodes.map(n => ({ ...n, selected: false })), newNode]);
    }, []); // Empty deps as we use ref

    useEffect(() => {
        const handleKeyDown = (e: KeyboardEvent) => {
            if (['INPUT', 'TEXTAREA'].includes((e.target as HTMLElement).tagName)) return;

            const { 
                undo, 
                redo, 
                save, 
                switchNext, 
                switchPrev, 
                switchCanvas, 
                assets, 
                storyboards, 
                getNodes, 
                getEdges, 
                setNodes, 
                setEdges, 
                saveHistory,
                clipboard
            } = latestValues.current;

            // Undo
            if ((e.metaKey || e.ctrlKey) && e.key === 'z' && !e.shiftKey) {
                e.preventDefault();
                undo?.();
            }

            // Redo
            if ((e.metaKey || e.ctrlKey) && (e.key === 'y' || (e.shiftKey && e.key === 'z'))) {
                e.preventDefault();
                redo?.();
            }

            // Create Group (Ctrl+G)
            if ((e.metaKey || e.ctrlKey) && e.key === 'g') {
                e.preventDefault();
                const { createGroup } = latestValues.current;
                const selectedCount = getNodes().filter(n => n.selected).length;
                if (selectedCount >= 2) {
                    createGroup?.();
                }
            }

            // Save
            if ((e.metaKey || e.ctrlKey) && e.key === 's') {
                e.preventDefault();
                save?.();
            }

            // Switch Canvas
            if (e.altKey && e.key === 'ArrowRight') {
                e.preventDefault();
                switchNext?.();
            }
            if (e.altKey && e.key === 'ArrowLeft') {
                e.preventDefault();
                switchPrev?.();
            }

            // Canvas Switching Shortcuts (Ctrl+Alt+1/2/3)
            if ((e.metaKey || e.ctrlKey) && e.altKey) {
                if (e.key === '1') {
                    e.preventDefault();
                    switchCanvas?.('main', 'main');
                } else if (e.key === '2' && assets.length > 0) {
                    e.preventDefault();
                    switchCanvas?.(assets[0].id, 'asset');
                } else if (e.key === '3' && storyboards.length > 0) {
                    e.preventDefault();
                    switchCanvas?.(storyboards[0].id, 'storyboard');
                }
            }

            // Delete
            if (e.key === 'Delete' || e.key === 'Backspace') {
                const selectedNodes = getNodes().filter(n => n.selected);
                const selectedEdges = getEdges().filter(e => e.selected);
                
                if (selectedNodes.length > 0 || selectedEdges.length > 0) {
                    saveHistory?.();
                }
                
                if (selectedNodes.length > 0) {
                    setNodes((nodes) => nodes.filter(n => !n.selected));
                }
                if (selectedEdges.length > 0) {
                    setEdges((edges) => edges.filter(e => !e.selected));
                }
            }

            // Copy
            if ((e.metaKey || e.ctrlKey) && e.key === 'c') {
                const selectedNodes = getNodes().filter(n => n.selected);
                if (selectedNodes.length === 1) {
                    latestValues.current.clipboard = selectedNodes[0] as AppNodeType; // Update ref directly
                    setClipboard(selectedNodes[0] as AppNodeType); // Trigger re-render
                }
            }

            // Paste
            if ((e.metaKey || e.ctrlKey) && e.key === 'v') {
                pasteNodes();
            }

            // Select All (Ctrl+A)
            if ((e.metaKey || e.ctrlKey) && e.key === 'a') {
                e.preventDefault();
                const allNodes = getNodes();
                if (allNodes.length > 0) {
                    setNodes((nodes) => nodes.map(n => ({ ...n, selected: true })));
                }
            }

            // Duplicate (Ctrl+D)
            if ((e.metaKey || e.ctrlKey) && e.key === 'd') {
                e.preventDefault();
                const selectedNodes = getNodes().filter(n => n.selected);
                if (selectedNodes.length > 0) {
                    saveHistory?.();
                    const currentNodes = getNodes();
                    const maxZIndex = currentNodes.reduce((max, node) => Math.max(max, node.zIndex ?? 0), 0);
                    
                    const newNodes = selectedNodes.map((node, index) => ({
                        ...node,
                        id: `appNode-${Date.now()}-${index}`,
                        position: {
                            x: node.position.x + 20,
                            y: node.position.y + 20
                        },
                        zIndex: maxZIndex + index + 1,
                        selected: true,
                        data: {
                            ...node.data,
                            title: node.data.title ? `${node.data.title} (Copy)` : 'Copy'
                        }
                    }));

                    // Deselect original nodes and add duplicated ones
                    setNodes((nodes) => [
                        ...nodes.map(n => ({ ...n, selected: false })),
                        ...newNodes
                    ]);
                }
            }

            // Deselect (Escape)
            if (e.key === 'Escape') {
                const hasSelection = getNodes().some(n => n.selected) || getEdges().some(e => e.selected);
                if (hasSelection) {
                    setNodes((nodes) => nodes.map(n => ({ ...n, selected: false })));
                    setEdges((edges) => edges.map(e => ({ ...e, selected: false })));
                }
            }

            // Fit View (Ctrl+0)
            if ((e.metaKey || e.ctrlKey) && e.key === '0') {
                e.preventDefault();
                // fitView will be called from the component using this hook
                // We'll emit a custom event for this
                window.dispatchEvent(new CustomEvent('canvas:fitView'));
            }

            // Zoom In (Ctrl++)
            if ((e.metaKey || e.ctrlKey) && (e.key === '=' || e.key === '+')) {
                e.preventDefault();
                window.dispatchEvent(new CustomEvent('canvas:zoomIn'));
            }

            // Zoom Out (Ctrl+-)
            if ((e.metaKey || e.ctrlKey) && e.key === '-') {
                e.preventDefault();
                window.dispatchEvent(new CustomEvent('canvas:zoomOut'));
            }

            // Toggle Fullscreen (F11)
            if (e.key === 'F11') {
                e.preventDefault();
                if (!document.fullscreenElement) {
                    document.documentElement.requestFullscreen().catch(() => {});
                } else {
                    document.exitFullscreen().catch(() => {});
                }
            }
        };

        window.addEventListener('keydown', handleKeyDown);
        return () => window.removeEventListener('keydown', handleKeyDown);
    }, [pasteNodes]); // pasteNodes is stable now

    return { setClipboard, clipboard, pasteNodes };
};
