import { SchemaReactflowNodeWithFunctions, SchemaReactflowRelationWithFunctions } from '../model/reactflow';
import Graph from 'graphology';
import { Attributes } from 'graphology-types';
import { MarkerType, Edge, Node } from 'reactflow';
import { QueryElementTypes } from '../../querybuilder';
import { SchemaGraphology } from '../model';

//TODO does not belong here; maybe should go into the GraphPolarisThemeProvider

export function schemaExpandRelation(graph: SchemaGraphology): SchemaGraphology {
  const newGraph = graph.copy();

  newGraph.forEachNode((node, attributes) => {
    newGraph.mergeNodeAttributes(node, { type: QueryElementTypes.Entity });
  });

  //makeNewRelationNodes
  graph.forEachEdge((edge, attributes, source, target): void => {
    const newID = 'RelationNode:' + edge;
    newGraph.addNode(newID, {
      ...attributes,
      name: edge,
      label: edge,
      attributes: { ...attributes.attributes },
      x: 0,
      y: 0,
      type: QueryElementTypes.Relation,
    });

    const id = 'RelationEdge' + source + '->' + newID;
    newGraph.addDirectedEdgeWithKey(id, source, newID, {
      name: edge,
    });

    const id2 = 'RelationEdge' + newID + '->' + target;
    newGraph.addDirectedEdgeWithKey(id2, newID, target, {});

    newGraph.dropEdge(edge);
  });

  return newGraph;
}

// Takes the schema as an input and creates basic react flow elements for them.
export function schemaGraphology2Reactflow(
  graph: Graph,
  defaultEdgeType: string,
  animatedEdges = false,
): {
  nodes: Array<Node<SchemaReactflowNodeWithFunctions | SchemaReactflowRelationWithFunctions>>;
  edges: Array<Edge>;
} {
  const initialElements: { nodes: Array<Node>; edges: Array<Edge> } = {
    nodes: [],
    edges: [],
  };

  initialElements.nodes = createReactFlowNodes(graph);
  initialElements.edges = createReactFlowEdges(graph, defaultEdgeType, animatedEdges);

  return initialElements;
}

export function createReactFlowNodes(graph: Graph): Array<Node> {
  const nodeElements: Array<Node> = [];
  graph.forEachNode((node: string, attributes: Attributes): void => {
    if (!Array.isArray(attributes.attributes)) {
      attributes.attributes = Object.values(attributes.attributes);
    }
    const newNode: Node = {
      id: node,
      data: {
        ...attributes,
      },
      position: { x: attributes.x, y: attributes.y },
      type: attributes.type,
    };
    nodeElements.push(newNode);
  });
  return nodeElements;
}

export function createReactFlowEdges(graph: Graph, defaultEdgeType: string, animatedEdges = false): Array<Edge> {
  const edgeElements: Array<Edge> = [];

  graph.forEachEdge((edge, attributes, source, target): void => {
    const newEdge: Edge = {
      id: edge,
      source: source,
      target: target,
      data: {
        ...attributes,
      },
      // label: edge,
      type: attributes?.type || defaultEdgeType,
      animated: animatedEdges,
      markerEnd: MarkerType.ArrowClosed, // TODO: Check
    };
    edgeElements.push(newEdge);
  });

  return edgeElements;
}