import type { Node } from '@xyflow/svelte';
import type { CustomNode, TinyflowOptions } from '../types';

export const DEFAULT_NODE_DRAG_HANDLE = '.tf-node-drag-handle';

export type TinyflowNodeNormalizer = (node: Node) => Node;

function shouldUseDefaultDragHandle(
  node: Node,
  customNodes?: Record<string, CustomNode>,
) {
  if (Object.prototype.hasOwnProperty.call(node, 'dragHandle')) {
    return false;
  }
  const customNode = node.type ? customNodes?.[node.type] : undefined;
  return customNode?.presentation !== 'plain';
}

export function createTinyflowNodeNormalizer(
  options?: TinyflowOptions,
): TinyflowNodeNormalizer {
  const readonly = options?.readonly === true;
  const nodesDraggable = options?.nodesDraggable ?? !readonly;
  const nodesConnectable = options?.nodesConnectable ?? !readonly;
  const elementsSelectable = options?.elementsSelectable ?? !readonly;

  return (node) => {
    let nextNode = node;
    const mutableNode = () => {
      if (nextNode === node) {
        nextNode = { ...node };
      }
      return nextNode;
    };

    if (nodesDraggable) {
      if (nextNode.draggable === false) {
        delete mutableNode().draggable;
      }
      if (shouldUseDefaultDragHandle(nextNode, options?.customNodes)) {
        mutableNode().dragHandle = DEFAULT_NODE_DRAG_HANDLE;
      }
    } else {
      if (nextNode.draggable !== false) {
        mutableNode().draggable = false;
      }
    }

    if (nodesConnectable) {
      if (nextNode.connectable === false) {
        delete mutableNode().connectable;
      }
    } else {
      if (nextNode.connectable !== false) {
        mutableNode().connectable = false;
      }
    }

    if (elementsSelectable) {
      if (nextNode.selectable === false) {
        delete mutableNode().selectable;
      }
    } else {
      if (nextNode.selectable !== false) {
        mutableNode().selectable = false;
      }
    }

    return nextNode;
  };
}
