// This program has been developed by students from the bachelor Computer Science at Utrecht
// University within the Software Project course.
// © Copyright Utrecht University (Department of Information and Computing Sciences)
// VisProgTypes.ts
import type {
  Edge,
  OnNodesChange,
  OnEdgesChange,
  OnConnect,
  OnReconnect,
  Node,
  OnEdgesDelete,
  OnNodesDelete, DeleteElementsOptions
} from '@xyflow/react';
import type {EditorWarningRegistry} from "./components/EditorWarnings.tsx";
import type {HandleRule} from "./HandleRuleLogic.ts";
import type { NodeTypes } from './NodeRegistry';
import type {FlowSnapshot} from "./EditorUndoRedo.ts";


/**
 * Type representing all registered node types.
 * This corresponds to the keys of NodeTypes in NodeRegistry.
 */
export type AppNode = typeof NodeTypes;

/**
 * The FlowState type defines the shape of the Zustand store used for managing the visual programming flow.
 *
 * Includes:
 * - Nodes and edges currently in the flow
 * - Callbacks for node and edge changes
 * - Node deletion and updates
 * - Edge reconnection handling
 */
export type FlowState = {
  nodes: Node[];
  edges: Edge[];
  edgeReconnectSuccessful: boolean;
  scrollable: boolean;

  /** Handler for managing scrollable state */
  setScrollable: (value: boolean) => void;

  /** Handler for changes to nodes triggered by ReactFlow */
  onNodesChange: OnNodesChange;

  onNodesDelete: OnNodesDelete;

  onEdgesDelete: OnEdgesDelete;

  /** Handler for changes to edges triggered by ReactFlow */
  onEdgesChange: OnEdgesChange;

  /** Handler for creating a new connection between nodes */
  onConnect: OnConnect;

  /** Handler for reconnecting an existing edge */
  onReconnect: OnReconnect;

  /** Called when an edge reconnect process starts */
  onReconnectStart: () => void;

  /**
   * Called when an edge reconnect process ends.
   * @param _ - event or unused parameter
   * @param edge - the edge that finished reconnecting
   */
  onReconnectEnd: (_: unknown, edge: Edge) => void;

  /**
   * Deletes a node and any connected edges.
   * @param nodeId - the ID of the node to delete
   */
  deleteNode: (nodeId: string,  deleteElements?: (params: DeleteElementsOptions) => Promise<{
    deletedNodes: Node[]
    deletedEdges: Edge[]
  }>) => void;

  /**
   * Replaces the current nodes array in the store.
   * @param nodes - new array of nodes
   */
  setNodes: (nodes: Node[]) => void;

  /**
   * Replaces the current edges array in the store.
   * @param edges - new array of edges
   */
  setEdges: (edges: Edge[]) => void;

  /**
   * Updates the data of a node by merging new data with existing node data.
   * @param nodeId - the ID of the node to update
   * @param data - object containing new data fields to merge
   */
  updateNodeData: (nodeId: string, data: object) => void;

  /**
   * Validates that all node names are unique across the workspace.
   */
  validateDuplicateNames: (nodes: Node[]) => void;

  /**
   * Adds a new node to the flow.
   * @param node - the Node object to add
   */
  addNode: (node: Node) => void;
} & UndoRedoState & HandleRuleRegistry & EditorWarningRegistry;

export type UndoRedoState = {
  // UndoRedo Types
  past: FlowSnapshot[];
  future: FlowSnapshot[];
  pushSnapshot: () => void;
  isBatchAction: boolean;
  beginBatchAction: () => void;
  endBatchAction: () => void;
  undo: () => void;
  redo: () => void;
}

export type HandleRuleRegistry = {
  ruleRegistry: Map<string, HandleRule[]>;

  getTargetRules: (
    targetNodeId: string,
    targetHandleId: string
  ) => HandleRule[];

  registerRules: (
    nodeId: string,
    handleId: string,
    rules: HandleRule[]
  ) => void;

  unregisterHandleRules: (
    nodeId: string,
    handleId: string
  ) => void;

  // cleans up all registered rules of all handles of the provided node
  unregisterNodeRules: (nodeId: string) => void
}



