'use client';
import React, { useCallback, useRef, DragEvent, useMemo, useState, useEffect } from 'react';
import {
  ReactFlow,
  MiniMap,
  Background,
  Connection,
  Node,
  ReactFlowProvider,
  useReactFlow,
  OnSelectionChangeParams,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { useHotkeys } from 'react-hotkeys-hook';

import { useNodesStore } from '@/stores/nodes-store';
import useFlowStore, { useFlowStoreActions } from '@/stores/flow-store';
import { useEditorStore } from '@/stores/editor-store';
import { useDesignStore } from '@/stores/design-store';
import { useSidebarStore } from '@/stores/sidebar-store';
import { useTemplateStore } from '@/stores/template-store';
import * as Tooltip from '@radix-ui/react-tooltip';
import { SendToBack } from 'lucide-react';
import AnimatedMessageEdge from '@/components/core/designer/edges/animated-messages/edge';
import { getNodeId } from '@/utils/react-flow';
import FlowControls from '@/components/core/designer/common/FlowControls';

import TemplateSelector from '@/modals/template-selector';
import SettingsModal from '@/modals/settings-modal';
import AutoLayoutModal from '@/modals/auto-layout-modal';

function FlowContent({ onAutoLayoutClick }: { onAutoLayoutClick: () => void }) {
  const reactFlowWrapper = useRef<HTMLDivElement>(null);
  const reactFlowInstance = useReactFlow();
  const { screenToFlowPosition, getNodes } = useReactFlow();

  const [lastSelection, setLastSelection] = useState<OnSelectionChangeParams | null>(null);
  const [lastCopiedSelection, setLastCopiedSelection] = useState<OnSelectionChangeParams | null>(null);
  const [contextMenuPosition, setContextMenuPosition] = useState<{ x: number; y: number } | null>(null);
  const [cursorPosition, setCursorPosition] = useState<{ x: number; y: number } | null>(null);

  const { nodes: applicationNodes } = useNodesStore();

  const { nodes: allNodes, edges } = useFlowStore();
  const { addNode, onNodesChange, onConnect, duplicateNode, setReactFlowInstance, undo, redo, exportFlow, importFlow, setEdges } = useFlowStoreActions();

  useEffect(() => {
    setReactFlowInstance(reactFlowInstance);
  }, [reactFlowInstance]);

  const { selectedNode, setSelectedNode } = useEditorStore();
  const { currentDesign, updateDesignName } = useDesignStore();
  const { toggleSidebar, showMinimap, showComments, selectedComponent, setSelectedComponent } = useSidebarStore();
  const { setShowTemplateSelector } = useTemplateStore();

  // Filter nodes based on comment visibility
  const nodes = React.useMemo(() => {
    if (showComments) {
      return allNodes;
    }
    // Hide comment thread nodes when showComments is false
    return allNodes.filter(node => node.type !== 'commentThread');
  }, [allNodes, showComments]);

  function handleCopy(e: KeyboardEvent) {
    // const multipleSelection = lastSelection?.nodes
    //   ? lastSelection?.nodes.length > 0
    //   : false;
    e.preventDefault();
    (e as unknown as Event).stopImmediatePropagation();
    if (window.getSelection()?.toString().length === 0 && lastSelection) {
      setLastCopiedSelection(lastSelection);
    }
  }

  function handlePaste(e: KeyboardEvent) {
    if (true) {
      e.preventDefault();
      (e as unknown as Event).stopImmediatePropagation();
      if (
        window.getSelection()?.toString().length === 0 &&
        lastCopiedSelection
      ) {
        // For each node int he array call the store to add the node
        for (const node of lastCopiedSelection?.nodes ?? []) {
          duplicateNode(node.id);
        }
      }
    }
  }

  function handleOpenDesigns(e: KeyboardEvent) {
    e.preventDefault();
    (e as unknown as Event).stopImmediatePropagation();
    openFromFile();
  }

  const openFromFile = () => {
    const fileInput = document.createElement('input');
    fileInput.type = 'file';
    fileInput.accept = '.ecstudio';
    fileInput.onchange = (e) => {
      const target = e.target as HTMLInputElement;
      const file = target?.files?.[0];
      if (file) {
        const reader = new FileReader();
        reader.onload = (event) => {
          try {
            const data = JSON.parse(event.target?.result as string);
            importFlow(data);
            // Update the current design name based on metadata (root level or nested) or filename
            const designName = data.name || data.metadata?.name || file.name.replace('.ecstudio', '');
            if (currentDesign?.id) {
              updateDesignName(currentDesign.id, designName);
            }
          } catch (error) {
            console.error('Error parsing file:', error);
            alert('Error: Invalid file format. Please select a valid .ecstudio file.');
          }
        }
        reader.readAsText(file);
      }
    }
    fileInput.click();
  }

  function handleUndo(e: KeyboardEvent) {
    e.preventDefault();
    (e as unknown as Event).stopImmediatePropagation();
    undo();
  }

  function handleRedo(e: KeyboardEvent) {
    e.preventDefault();
    (e as unknown as Event).stopImmediatePropagation();
    redo();
  }

  function handleToggleSidebar(e: KeyboardEvent) {
    e.preventDefault();
    (e as unknown as Event).stopImmediatePropagation();
    toggleSidebar();
  }

  function handleSelectAll(e: KeyboardEvent) {
    e.preventDefault();
    (e as unknown as Event).stopImmediatePropagation();
    // Select all nodes
    const nodeUpdates = nodes.map(node => ({
      id: node.id,
      type: 'select' as const,
      selected: true
    }));
    onNodesChange(nodeUpdates);
  }

  function handleSaveToFile(e: KeyboardEvent) {
    e.preventDefault();
    (e as unknown as Event).stopImmediatePropagation();
    
    const data = exportFlow();
    
    // Check if the browser supports the File System Access API
    if ('showSaveFilePicker' in window) {
      // Modern browsers with File System Access API
      const saveFileWithPicker = async () => {
        try {
          const fileHandle = await (window as any).showSaveFilePicker({
            suggestedName: `${currentDesign?.name || 'design'}.ecstudio`,
            types: [{
              description: 'EventCatalog Studio files',
              accept: { 'application/json': ['.ecstudio'] }
            }]
          });
          
          const writable = await fileHandle.createWritable();
          await writable.write(JSON.stringify(data, null, 2));
          await writable.close();
        } catch (error) {
          // User cancelled or other error
          if (error instanceof Error && error.name !== 'AbortError') {
            console.error('Error saving file:', error);
          }
        }
      };
      saveFileWithPicker();
    } else {
      // Fallback for browsers without File System Access API
      const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `${currentDesign?.name || 'design'}.ecstudio`;
      a.click();
      URL.revokeObjectURL(url);
    }
  }

  // @ts-ignore
  useHotkeys('mod+c', handleCopy);
  // @ts-ignore
  useHotkeys('mod+v', handlePaste);
  // @ts-ignore
  useHotkeys('mod+o', handleOpenDesigns);
  // @ts-ignore
  useHotkeys('mod+z', handleUndo);
  // @ts-ignore
  useHotkeys('mod+shift+z', handleRedo);
  // @ts-ignore
  useHotkeys('mod+b', handleToggleSidebar);
  // @ts-ignore
  useHotkeys('mod+a', handleSelectAll);
  // @ts-ignore
  useHotkeys('mod+s', handleSaveToFile);
  // @ts-ignore
  useHotkeys('mod+n', () => setShowTemplateSelector(true));

  const nodeTypes = applicationNodes.reduce((acc: any, node: any) => {
    acc[node.type] = node.component;
    return acc;
  }, {});

  const edgeTypes = useMemo(() => ({
    animatedMessage: AnimatedMessageEdge,
  }), []);


  const onDragOver = useCallback((event: DragEvent) => {
    event.preventDefault();
    event.dataTransfer.dropEffect = 'move';
  }, []);

  const onDrop = useCallback(
    (event: DragEvent) => {
      event.preventDefault();
      const dataString = event.dataTransfer.getData('application/reactflow');
      if (!dataString) return;
      const { nodeType, label, data } = JSON.parse(dataString);

      const position = screenToFlowPosition({ x: event.clientX, y: event.clientY });

      const newNode: Node = {
        id: getNodeId(nodeType),
        type: nodeType,
        position,
        data: data ?? { label },
      };

      addNode(newNode);

    },
    [screenToFlowPosition, getNodes]
  );

  const handleNodesChange = useCallback((changes: any) => {
    onNodesChange(changes);
  }, [onNodesChange]);

  const handleConnect = useCallback((connection: Connection) => {
    onConnect(connection);
  }, [onConnect]);

  const onEdgesChange = useCallback((changes: any) => {
    // Handle edge changes if needed
  }, []);

  const onSelectionChange = useCallback(
    (flow: OnSelectionChangeParams): void => {
      const isGroupSelection = flow.nodes.length > 1;
      setLastSelection(flow);

      // if (!isGroupSelection) {
      //   setSelectedNode(flow.nodes[0]);
      // }
    },
    [],
  );

  const onPaneClick = useCallback((event: React.MouseEvent) => {
    const position = screenToFlowPosition({ x: event.clientX, y: event.clientY });
    
    // If a component is selected, place it at click position
    if (selectedComponent) {
      const newNode: Node = {
        id: getNodeId(selectedComponent.nodeType),
        type: selectedComponent.nodeType,
        position,
        data: { ...selectedComponent.data, label: selectedComponent.label },
      };
      addNode(newNode);
      setSelectedComponent(null); // Clear selection after placing
      return;
    }

    if(selectedNode) {
      setSelectedNode(null);
      reactFlowInstance?.fitView({ duration: 1000 });
    }
  }, [setSelectedNode, reactFlowInstance, selectedNode, selectedComponent, setSelectedComponent, screenToFlowPosition, addNode]);

  const handleContextMenu = useCallback((event: React.MouseEvent) => {
    event.preventDefault();
    const position = screenToFlowPosition({ x: event.clientX, y: event.clientY });
    setContextMenuPosition(position);
  }, [screenToFlowPosition]);

  const handleMouseMove = useCallback((event: React.MouseEvent) => {
    if (selectedComponent) {
      setCursorPosition({ x: event.clientX, y: event.clientY });
    } else {
      setCursorPosition(null);
    }
  }, [selectedComponent]);

  const handleAutoLayoutClick = () => {
    onAutoLayoutClick();
  };

  return (
    <div 
      className={`w-full h-full relative ${selectedComponent ? 'cursor-none' : ''}`}
      ref={reactFlowWrapper}
      onContextMenu={handleContextMenu}
      onMouseMove={handleMouseMove}
    >
      {/* Auto Layout Button - Top Left */}
      <Tooltip.Provider>
        <div className="absolute top-2 left-2 z-10">
          <Tooltip.Root>
            <Tooltip.Trigger asChild>
              <button
                onClick={handleAutoLayoutClick}
                className="bg-white rounded-lg p-2  border border-gray-200 hover:bg-gray-50 transition-colors"
              >
                <SendToBack className="h-4 w-4 text-gray-600" />
              </button>
            </Tooltip.Trigger>
            <Tooltip.Portal>
              <Tooltip.Content
                className="bg-gray-900 text-white px-2 py-1 rounded text-sm z-50"
                sideOffset={5}
                side="right"
              >
                Reorder Diagram
                <Tooltip.Arrow className="fill-gray-900" />
              </Tooltip.Content>
            </Tooltip.Portal>
          </Tooltip.Root>
        </div>
      </Tooltip.Provider>
      
      <FlowControls />
      
      {/* <CanvasContextMenu position={contextMenuPosition}> */}
        <ReactFlow
          nodes={nodes}
          edges={edges}
          nodeTypes={nodeTypes}
          edgeTypes={edgeTypes}
          onNodesChange={handleNodesChange}
          onEdgesChange={onEdgesChange}
          zoomOnScroll={false}
          panOnScroll={true}
          panOnScrollSpeed={1.2}
          onSelectionChange={onSelectionChange}
          onConnect={handleConnect}
          onDragOver={onDragOver}
          onDrop={onDrop}
          onPaneClick={onPaneClick}
        >
          {showMinimap && <MiniMap />}
          <Background gap={10} bgColor='#f5f5f5' />
        </ReactFlow>
      {/* </CanvasContextMenu> */}

      {/* Cursor Preview */}
      {selectedComponent && cursorPosition && (
        <div
          className="fixed pointer-events-none z-50 bg-white border border-gray-300 rounded-md shadow-lg p-2 opacity-75"
          style={{
            left: cursorPosition.x + 10,
            top: cursorPosition.y + 10,
            transform: 'translate(0, 0)'
          }}
        >
          <div className="flex items-center space-x-2">
            {selectedComponent.iconComponent && (
              <selectedComponent.iconComponent 
                size={16} 
                className={`text-${selectedComponent.iconColor || 'gray'}-600`} 
              />
            )}
            <span className="text-xs text-gray-700 whitespace-nowrap">
              {selectedComponent.label}
            </span>
          </div>
        </div>
      )}
    </div>
  );
}

export default function App() {
  const [showAutoLayoutDialog, setShowAutoLayoutDialog] = useState(false);
  const { autoLayout } = useFlowStoreActions();

  const handleAutoLayoutClick = () => {
    setShowAutoLayoutDialog(true);
  };

  return (
    <ReactFlowProvider>
      <FlowContent onAutoLayoutClick={handleAutoLayoutClick} />
      <TemplateSelector />
      <SettingsModal />
      <AutoLayoutModal 
        isOpen={showAutoLayoutDialog} 
        onClose={() => setShowAutoLayoutDialog(false)}
        onConfirm={autoLayout}
      />
    </ReactFlowProvider>
  );
}