import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import type { RootState } from './store';
import Graph from 'graphology';

/*************** schema format from the backend *************** */
// TODO: should probably not live here
/** Schema type, consist of nodes and edges */
export type SchemaFromBackend = {
  edges: Edge[];
  nodes: Node[];
};

/** Attribute type, consist of a name */
export type Attribute = {
  name: string;
  type: 'string' | 'int' | 'bool' | 'float';
};

/** Node type, consist of a name and a list of attributes */
export type Node = {
  name: string;
  attributes: Attribute[];
};

/** Edge type, consist of a name, start point, end point and a list of attributes */
export type Edge = {
  name: string;
  to: string;
  from: string;
  collection: string;
  attributes: Attribute[];
};
/**************************************************************** */

// Define the initial state using that type
export const initialState = {
  graphologySerialized: new Graph().export(),
};

export const schemaSlice = createSlice({
  name: 'schema',
  // `createSlice` will infer the state type from the `initialState` argument
  initialState,
  reducers: {
    setSchema: (state, action: PayloadAction<Graph>) => {
      state.graphologySerialized = action.payload.export();
    },

    readInSchemaFromBackend: (
      state,
      action: PayloadAction<SchemaFromBackend>
    ) => {
      const { nodes, edges } = action.payload;
      // Instantiate a directed graph that allows self loops and parallel edges
      const schema = new Graph({ allowSelfLoops: true, multi: true });
      console.log('Updating schema');
      // The graph schema needs a node for each node AND edge. These need then be connected

      nodes.forEach((node) => {
        schema.addNode(node.name, {
          name: node.name,
          attributes: node.attributes,
          x: 0,
          y: 0,
        });
      });

      // The name of the edge will be name + from + to, since edge names are not unique
      edges.forEach((edge) => {
        const edgeID = edge.name + edge.from + edge.to;

        // This node is the actual edge
        schema.addNode(edgeID, {
          name: edge.name,
          attributes: edge.attributes,
          from: edge.from,
          to: edge.to,
          collection: edge.collection,
          x: 0,
          y: 0,
        });

        // These lines are simply for keeping the schema together
        schema.addDirectedEdgeWithKey(edgeID + 'f', edge.from, edgeID);
        schema.addDirectedEdgeWithKey(edgeID + 't', edgeID, edge.to);
      });

      state.graphologySerialized = schema.export();
    },
  },
});

export const { readInSchemaFromBackend, setSchema } = schemaSlice.actions;

// Select the schema and convert it to a graphology object
export const selectSchema = (state: RootState) =>
  Graph.from(state.schema.graphologySerialized);

export default schemaSlice.reducer;