import { useCallback } from 'react';
import { Edge, Position } from '@xyflow/react';
import { WorkflowReactFlowNode } from '../types/reactflow';
import { useAppSelector, useDialogState } from '../stores';
import { autoLayoutNodes } from '../utils/transforms';
import { reconnectEdgesAfterDeletion } from '../utils/edgeReconnection';
import {
  getAppNameFromIntegration,
  getAppServiceInfo,
  getActionDisplayName,
  getActionIconName,
  getTriggerDisplayName,
  getTriggerIconName,
} from '../utils/display';

interface AppItem {
  id: string;
  name: string;
  icon: string;
  integration?: string;
}

/**
 * Combined options for all canvas-level user actions
 */
export interface UseCanvasActionsOptions {
  /** Current nodes */
  nodes: WorkflowReactFlowNode[];
  /** Current edges */
  edges: Edge[];
  /** Function to update nodes */
  setNodes: (
    updater:
      | WorkflowReactFlowNode[]
      | ((nodes: WorkflowReactFlowNode[]) => WorkflowReactFlowNode[]),
  ) => void;
  /** Function to update edges */
  setEdges: (updater: Edge[] | ((edges: Edge[]) => Edge[])) => void;
  /** Function to take a snapshot for undo (call before modifications) */
  takeSnapshot: (nodes: WorkflowReactFlowNode[], edges: Edge[]) => void;
  /** Callback when a node is selected */
  setSelectedNodeId: (id: string | null) => void;
}

/**
 * Return type for useCanvasActions hook
 */
export interface UseCanvasActionsReturn {
  /** Add a new placeholder node (trigger or action) */
  handleAddPlaceholder: (type: 'trigger' | 'action', parentNodeId?: string, sourceHandle?: string) => void;
  /** Request deletion of a node (opens confirmation dialog) */
  handleRequestDeleteNode: (nodeId: string) => void;
  /** Confirm and execute node deletion */
  handleConfirmDeleteNode: () => void;
  /** Cancel node deletion */
  handleCancelDeleteNode: () => void;
  /** Handle app/action selection from sidebar (converts placeholder to real node) */
  handleAppSelected: (item: AppItem) => void;
  /** Handle closing the app selector (removes unconfigured placeholder) */
  handleCloseAppSelector: () => void;
}

/**
 * Custom hook for managing all canvas-level user actions.
 *
 * Combines node operations (add, delete) and app selection (placeholder
 * conversion) into a single cohesive hook. This reduces the number of hooks
 * FlowBuilder needs to orchestrate and keeps related canvas logic together.
 *
 * @example
 * ```tsx
 * const canvasActions = useCanvasActions({
 *   nodes,
 *   edges,
 *   setNodes,
 *   setEdges,
 *   takeSnapshot,
 *   setSelectedNodeId,
 * });
 *
 * // Add new action at end
 * canvasActions.handleAddPlaceholder('action');
 *
 * // Convert placeholder to real node
 * canvasActions.handleAppSelected({ id: 'wordpress/create_post', name: 'Create Post', icon: 'FilePlus' });
 * ```
 */
export function useCanvasActions(options: UseCanvasActionsOptions): UseCanvasActionsReturn {
  const { nodes, edges, setNodes, setEdges, takeSnapshot, setSelectedNodeId } = options;

  // Get UI store functions for app selector and delete confirmation
  const { selectedPlaceholderId, openAppSelector, closeAppSelector } = useAppSelector();
  const { nodeToDelete, requestDeleteNode, cancelDeleteNode, clearNodeToDelete } = useDialogState();

  // ---------------------------------------------------------------------------
  // Node Operations
  // ---------------------------------------------------------------------------

  /**
   * Add a new placeholder node (trigger or action)
   */
  const handleAddPlaceholder = useCallback(
    (type: 'trigger' | 'action', parentNodeId?: string, sourceHandle?: string) => {
      takeSnapshot(nodes, edges);

      const nodeId = type === 'trigger' ? 'node-trigger' : `node-${Date.now()}`;

      // Create placeholder node
      const newNode: WorkflowReactFlowNode = {
        id: nodeId,
        type: type,
        position: { x: 250, y: 80 + nodes.length * 160 },
        sourcePosition: Position.Bottom,
        targetPosition: Position.Top,
        data: {
          name: type === 'trigger' ? 'Choose a trigger' : 'Choose an action',
          icon: 'Plus',
          status: 'placeholder',
          placeholderType: type,
          config: {},
        },
      };

      // Build new edge before layout so autoLayoutNodes positions the node correctly
      let newEdge: Edge | null = null;
      if (type === 'action' && nodes.length > 0) {
        const parentId = parentNodeId ?? nodes[nodes.length - 1].id;
        newEdge = {
          id: sourceHandle
            ? `e-${parentId}-${sourceHandle}-${nodeId}`
            : `e-${parentId}-${nodeId}`,
          source: parentId,
          target: nodeId,
          ...(sourceHandle ? { sourceHandle } : {}),
          type: 'insertStep',
        };
      }

      const layoutEdges = newEdge ? [...edges, newEdge] : edges;
      setNodes((nds) => {
        const newNodes = [...nds, newNode];
        return autoLayoutNodes(newNodes as WorkflowReactFlowNode[], layoutEdges);
      });

      if (newEdge) {
        setEdges((eds) => [...eds, newEdge!]);
      }

      // Open app selector immediately
      openAppSelector(type, nodeId);
    },
    [nodes, edges, setNodes, setEdges, takeSnapshot, openAppSelector],
  );

  /**
   * Request deletion of a node (opens confirmation dialog)
   */
  const handleRequestDeleteNode = useCallback(
    (nodeId: string) => {
      const node = nodes.find((n) => n.id === nodeId);
      if (node) {
        requestDeleteNode(nodeId, node.data.name);
      }
    },
    [nodes, requestDeleteNode],
  );

  /**
   * Confirm and execute node deletion
   */
  const handleConfirmDeleteNode = useCallback(() => {
    if (!nodeToDelete) return;

    // Take snapshot for undo before deleting node
    takeSnapshot(nodes, edges);

    // Capture the ID before clearing state
    const deletedNodeId = nodeToDelete.id;

    // Clear dialog state first
    clearNodeToDelete();

    // Phase 1: Remove deleted node and mark remaining nodes as animating
    setNodes((nds) => {
      const filteredNodes = nds.filter((n) => n.id !== deletedNodeId);
      // Set animation flag before position changes
      return filteredNodes.map((n) => ({
        ...n,
        data: { ...n.data, isAnimating: true },
      }));
    });

    // Compute reconnected edges synchronously so both setEdges and the rAF
    // callback reference the same stable value (no closure timing dependency).
    const reconnectedEdges = reconnectEdgesAfterDeletion(deletedNodeId, edges);
    setEdges(reconnectedEdges);

    // Phase 2: Wait for next frame, then apply new positions with animation
    requestAnimationFrame(() => {
      setNodes((nds) => {
        const layoutNodes = autoLayoutNodes(nds, reconnectedEdges);
        // Clear animation flag after positions are set
        return layoutNodes.map((n) => ({
          ...n,
          data: { ...n.data, isAnimating: false },
        }));
      });
    });
  }, [nodeToDelete, setNodes, setEdges, takeSnapshot, nodes, edges, clearNodeToDelete]);

  /**
   * Cancel node deletion
   */
  const handleCancelDeleteNode = useCallback(() => {
    cancelDeleteNode();
  }, [cancelDeleteNode]);

  // ---------------------------------------------------------------------------
  // App Selection (placeholder -> real node conversion)
  // ---------------------------------------------------------------------------

  /**
   * Handle when user selects an app from the AppSelectorPanel.
   * Converts the placeholder node to a real action/trigger node.
   */
  const handleAppSelected = useCallback(
    (item: AppItem) => {
      if (!selectedPlaceholderId) return;

      const appInfo = item.integration
        ? { appName: getAppNameFromIntegration(item.integration), appService: item.integration }
        : getAppServiceInfo(item.id);

      const placeholderNode = nodes.find((n) => n.id === selectedPlaceholderId);
      const nodeType = placeholderNode?.data.placeholderType || 'action';

      setNodes((nds) =>
        nds.map((node) => {
          if (node.id === selectedPlaceholderId) {
            return {
              ...node,
              data: {
                ...node.data,
                name:
                  nodeType === 'trigger'
                    ? item.name || getTriggerDisplayName(item.id)
                    : item.name || getActionDisplayName(item.id),
                icon:
                  nodeType === 'trigger' ? getTriggerIconName(item.id) : getActionIconName(item.id),
                status: 'unconfigured' as const,
                actionType: item.id,
                appName: appInfo.appName,
                appService: appInfo.appService,
                placeholderType: undefined,
              },
            };
          }
          return node;
        }),
      );

      setSelectedNodeId(selectedPlaceholderId);
      closeAppSelector();
    },
    [selectedPlaceholderId, nodes, setNodes, setSelectedNodeId, closeAppSelector],
  );

  /**
   * Handle closing the app selector.
   * If there's a placeholder node that hasn't been configured, remove it.
   */
  const handleCloseAppSelector = useCallback(() => {
    if (selectedPlaceholderId) {
      const placeholderNode = nodes.find((n) => n.id === selectedPlaceholderId);
      if (placeholderNode?.data.status === 'placeholder') {
        setNodes((nds) => nds.filter((n) => n.id !== selectedPlaceholderId));
        setEdges((eds) =>
          eds.filter(
            (e) => e.source !== selectedPlaceholderId && e.target !== selectedPlaceholderId,
          ),
        );
      }
    }
    closeAppSelector();
  }, [selectedPlaceholderId, nodes, setNodes, setEdges, closeAppSelector]);

  return {
    handleAddPlaceholder,
    handleRequestDeleteNode,
    handleConfirmDeleteNode,
    handleCancelDeleteNode,
    handleAppSelected,
    handleCloseAppSelector,
  };
}
