import { vi } from 'vitest';
import React from 'react';

// Mock ReactFlow component
export const ReactFlow = ({
  children,
  nodes,
  edges,
}: {
  children?: React.ReactNode;
  nodes?: unknown[];
  edges?: unknown[];
  [key: string]: unknown;
}) => (
  <div
    data-testid="react-flow-mock"
    data-nodes={JSON.stringify(nodes)}
    data-edges={JSON.stringify(edges)}
  >
    {children}
  </div>
);

// Mock ReactFlowProvider
export const ReactFlowProvider = ({ children }: { children: React.ReactNode }) => (
  <div data-testid="react-flow-provider">{children}</div>
);

// Mock useNodesState hook
export const useNodesState = <T,>(initialNodes: T[] = []) => {
  const [nodes, setNodes] = React.useState(initialNodes);
  const onNodesChange = vi.fn();
  return [nodes, setNodes, onNodesChange] as const;
};

// Mock useEdgesState hook
export const useEdgesState = <T,>(initialEdges: T[] = []) => {
  const [edges, setEdges] = React.useState(initialEdges);
  const onEdgesChange = vi.fn();
  return [edges, setEdges, onEdgesChange] as const;
};

// Mock useReactFlow hook
export const useReactFlow = () => ({
  getNodes: vi.fn(() => []),
  getEdges: vi.fn(() => []),
  setNodes: vi.fn(),
  setEdges: vi.fn(),
  addNodes: vi.fn(),
  addEdges: vi.fn(),
  deleteElements: vi.fn(),
  fitView: vi.fn(),
  zoomIn: vi.fn(),
  zoomOut: vi.fn(),
  getViewport: vi.fn(() => ({ x: 0, y: 0, zoom: 1 })),
  setViewport: vi.fn(),
  screenToFlowPosition: vi.fn((pos: { x: number; y: number }) => pos),
  flowToScreenPosition: vi.fn((pos: { x: number; y: number }) => pos),
  getIntersectingNodes: vi.fn(() => []),
  isNodeIntersecting: vi.fn(() => false),
  updateNode: vi.fn(),
  updateNodeData: vi.fn(),
});

// Mock useOnSelectionChange hook
export const useOnSelectionChange = vi.fn();

// Mock useUpdateNodeInternals hook
export const useUpdateNodeInternals = () => vi.fn();

// Position enum
export const Position = {
  Left: 'left',
  Right: 'right',
  Top: 'top',
  Bottom: 'bottom',
} as const;

// MarkerType enum
export const MarkerType = {
  Arrow: 'arrow',
  ArrowClosed: 'arrowclosed',
} as const;

// Mock Handle component
export const Handle = ({
  children,
  ...props
}: {
  children?: React.ReactNode;
  [key: string]: unknown;
}) => (
  <div data-testid="react-flow-handle" {...props}>
    {children}
  </div>
);

// Mock Background component
export const Background = () => <div data-testid="react-flow-background" />;

// Mock Controls component
export const Controls = () => <div data-testid="react-flow-controls" />;

// Mock MiniMap component
export const MiniMap = () => <div data-testid="react-flow-minimap" />;

// Mock Panel component
export const Panel = ({
  children,
  ...props
}: {
  children?: React.ReactNode;
  [key: string]: unknown;
}) => (
  <div data-testid="react-flow-panel" {...props}>
    {children}
  </div>
);

// Mock BaseEdge component
export const BaseEdge = (props: Record<string, unknown>) => (
  <path data-testid="react-flow-base-edge" {...props} />
);

// Mock getBezierPath function
export const getBezierPath = () => ['M0,0 C0,0 0,0 0,0', 0, 0];

// Mock getSmoothStepPath function
export const getSmoothStepPath = () => ['M0,0 L0,0', 0, 0];

// Mock getStraightPath function
export const getStraightPath = () => ['M0,0 L0,0', 0, 0];

// Mock applyNodeChanges function
export const applyNodeChanges = vi.fn((_changes, nodes) => nodes);

// Mock applyEdgeChanges function
export const applyEdgeChanges = vi.fn((_changes, edges) => edges);

// Mock addEdge function
export const addEdge = vi.fn((edge, edges) => [...edges, edge]);

// Type exports (empty objects for type compatibility)
export type Node<T = unknown> = {
  id: string;
  type?: string;
  position: { x: number; y: number };
  data: T;
  sourcePosition?: string;
  targetPosition?: string;
  selected?: boolean;
  dragging?: boolean;
};

export type Edge = {
  id: string;
  source: string;
  target: string;
  sourceHandle?: string;
  targetHandle?: string;
  type?: string;
  animated?: boolean;
  style?: React.CSSProperties;
};

export type NodeChange = {
  type: string;
  id?: string;
  [key: string]: unknown;
};

export type EdgeChange = {
  type: string;
  id?: string;
  [key: string]: unknown;
};

export type Connection = {
  source: string;
  target: string;
  sourceHandle?: string;
  targetHandle?: string;
};
