import {
  Background,
  Controls,
  Panel,
  ReactFlow,
  ReactFlowProvider,
  MarkerType,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import {useShallow} from 'zustand/react/shallow';
import {DndToolbar} from './visualProgrammingUI/components/DragDropSidebar.tsx';
import useFlowStore from './visualProgrammingUI/VisProgStores.tsx';
import type {FlowState} from './visualProgrammingUI/VisProgTypes.tsx';
import styles from './VisProg.module.css'
import { NodeReduces, NodeTypes } from './visualProgrammingUI/NodeRegistry.ts';

// --| config starting params for flow |--


/**
 * defines how the default edge looks inside the editor
 */
const DEFAULT_EDGE_OPTIONS = {
  type: 'default',
  markerEnd: {
    type: MarkerType.ArrowClosed,
    color: '#505050',
  },
};


/**
 * defines what functions in the FlowState store map to which names,
 * @param state
 */
const selector = (state: FlowState) => ({
  nodes: state.nodes,
  edges: state.edges,
  onNodesChange: state.onNodesChange,
  onEdgesChange: state.onEdgesChange,
  onConnect: state.onConnect,
  onReconnectStart: state.onReconnectStart,
  onReconnectEnd: state.onReconnectEnd,
  onReconnect: state.onReconnect
});

// --| define ReactFlow editor |--

/**
 * Defines the ReactFlow visual programming editor component
 * any implementations of editor logic should be encapsulated where possible
 * so the Component definition stays as readable as possible
 * @constructor
 */
const VisProgUI = () => {
  const {
    nodes, edges,
    onNodesChange,
    onEdgesChange,
    onConnect,
    onReconnect,
    onReconnectStart,
    onReconnectEnd
  } = useFlowStore(useShallow(selector)); // instructs the editor to use the corresponding functions from the FlowStore

  return (
    <div className={`${styles.innerEditorContainer} round-lg border-lg`}>
      <ReactFlow
        nodes={nodes}
        edges={edges}
        defaultEdgeOptions={DEFAULT_EDGE_OPTIONS}
        nodeTypes={NodeTypes}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onReconnect={onReconnect}
        onReconnectStart={onReconnectStart}
        onReconnectEnd={onReconnectEnd}
        onConnect={onConnect}
        snapToGrid
        fitView
        proOptions={{hideAttribution: true}}
      >
        <Panel position="top-center" className={styles.dndPanel}>
          <DndToolbar/> {/* contains the drag and drop panel for nodes */}
        </Panel>
        <Controls/>
        <Background/>
      </ReactFlow>
    </div>
  );
};



/**
 * Places the VisProgUI component inside a ReactFlowProvider
 *
 * Wrapping the editor component inside a ReactFlowProvider
 * allows us to access and interact with the components inside the editor, outside the editor definition,
 * thus facilitating the addition of node specific functions inside their node definitions
 */
function VisualProgrammingUI() {
  return (
    <ReactFlowProvider>
      <VisProgUI/>
    </ReactFlowProvider>
  );
}

// currently outputs the prepared program to the console
function runProgram() {
  const program = graphReducer();
  console.log(program);
  console.log(JSON.stringify(program, null, 2));
}

/**
 * Reduces the graph into its phases' information and recursively calls their reducing function
 */ 
function graphReducer() {
  const { nodes } = useFlowStore.getState();
  return nodes
    .filter((n) => n.type == 'phase')
    .map((n) => {
      const reducer = NodeReduces['phase'];
      return reducer(n, nodes)
    }); 
}

/**
 * houses the entire page, so also UI elements
 * that are not a part of the Visual Programming UI
 * @constructor
 */
function VisProgPage() {
  return (
    <>
      <VisualProgrammingUI/>
      <button onClick={runProgram}>run program</button>
    </>
  )
}

export default VisProgPage
