import { useCallback } from 'react';
import {
  ReactFlow,
  Controls,
  MiniMap,
  Background,
  Connection,
  Edge,
  NodeChange,
  BackgroundVariant,
  EdgeChange,
} from '@xyflow/react';
import type { NodeTypes, IsValidConnection } from '@xyflow/react';
import { ViewportController } from '../../hooks/useViewportController';
import WorkflowReactFlowNode from '../WorkflowReactFlowNode';
import AddStepNode from '../AddStepNode';
import { WorkflowReactFlowNode as WorkflowReactFlowNodeType } from '../../types/reactflow';

/**
 * Node types defined outside the component to avoid re-renders.
 * Cast needed because React Flow's NodeTypes uses {data: any, type: any}
 * which doesn't structurally match our typed NodeProps<WorkflowReactFlowNode>.
 */
const nodeTypes: NodeTypes = {
  trigger: WorkflowReactFlowNode,
  action: WorkflowReactFlowNode,
  operator: WorkflowReactFlowNode,
  addStep: AddStepNode,
} as NodeTypes;

/** Edge types (removed InsertStepEdge - Pro plugin feature) */
const edgeTypes = {};

export interface FlowCanvasProps {
  /** Display nodes (with callbacks attached, including addStep pseudo-node) */
  nodes: WorkflowReactFlowNodeType[];
  /** Edges with insert button data */
  edges: Edge[];
  /** Handler for node changes (filtered to exclude position changes) */
  onNodesChange: (changes: NodeChange<WorkflowReactFlowNodeType>[]) => void;
  /** Handler for edge changes */
  onEdgesChange: (changes: EdgeChange[]) => void;
  /** Handler for new connections */
  onConnect: (connection: Connection) => void;
  /** Handler for node clicks */
  onNodeClick: (event: React.MouseEvent, node: WorkflowReactFlowNodeType) => void;
  /** Raw nodes for validation lookups */
  rawNodes: WorkflowReactFlowNodeType[];
  /** Whether a sidebar config panel is open (for viewport adjustment) */
  sidebarOpen: boolean;
  /** Whether the workflow is loading */
  loading: boolean;
}

/**
 * FlowCanvas encapsulates the ReactFlow instance and its configuration.
 *
 * Renders the visual workflow canvas with background, controls, minimap,
 * and viewport controller. Shows a loading spinner while the workflow is loading.
 */
export function FlowCanvas({
  nodes,
  edges,
  onNodesChange,
  onEdgesChange,
  onConnect,
  onNodeClick,
  rawNodes,
  sidebarOpen,
  loading,
}: FlowCanvasProps) {
  // Connection validation
  const isValidConnection = useCallback(
    (connection: Connection) => {
      const sourceNode = rawNodes.find((n) => n.id === connection.source);
      const targetNode = rawNodes.find((n) => n.id === connection.target);
      if (!sourceNode || !targetNode) return false;
      if (sourceNode.type === 'trigger' && targetNode.type === 'trigger') return false;
      if (sourceNode.type === 'action' && targetNode.type === 'trigger') return false;
      return true;
    },
    [rawNodes],
  );

  if (loading) {
    return (
      <div className="flex items-center justify-center h-full bg-[var(--wf-neutral-50)]">
        <div className="text-center">
          <div className="inline-block animate-spin rounded-full h-10 w-10 border-2 border-[var(--wf-neutral-200)] border-t-[var(--wf-action)]" />
          <p className="mt-4 text-[var(--wf-neutral-500)] text-sm">Loading workflow...</p>
        </div>
      </div>
    );
  }

  return (
    <ReactFlow
      nodes={nodes}
      edges={edges}
      onNodesChange={onNodesChange}
      onEdgesChange={onEdgesChange}
      onConnect={onConnect}
      onNodeClick={onNodeClick}
      nodeTypes={nodeTypes}
      edgeTypes={edgeTypes}
      isValidConnection={isValidConnection as IsValidConnection}
      nodesDraggable={false}
      nodesConnectable={false}
      elementsSelectable={true}
      fitView
      fitViewOptions={{ padding: 0.2, maxZoom: 1 }}
      minZoom={0.5}
      maxZoom={2}
      deleteKeyCode={null}
      defaultEdgeOptions={{
        type: 'insertStep',
        animated: false,
        style: { stroke: 'var(--wf-neutral-300)', strokeWidth: 1.5 },
      }}
    >
      <ViewportController sidebarOpen={sidebarOpen} nodeCount={rawNodes.length} />
      <Background
        color="var(--wf-neutral-200)"
        gap={24}
        variant={BackgroundVariant.Cross}
        size={1}
      />
      <Controls position="bottom-right" />
      <MiniMap
        position="bottom-left"
        nodeColor={(node) => (node.type === 'trigger' ? 'var(--wf-trigger)' : 'var(--wf-action)')}
        maskColor="rgba(0, 0, 0, 0.04)"
      />
    </ReactFlow>
  );
}
