'use client';

import { useCallback, useMemo } from 'react';
import {
  Edge,
  EdgeChange,
  Node,
  NodeChange,
  NodeTypes,
  ProOptions,
  ReactFlow,
  useEdgesState,
  useNodesState,
  useViewport
} from 'reactflow';

import Overlay from '@/components/ui/Overlay';
import AnimateFade from '@/components/wrap/AnimateFade';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { useOSS } from '@/context/OssContext';

import { useOssEdit } from '../OssEditContext';
import InputNode from './InputNode';
import OperationNode from './OperationNode';
import ToolbarOssGraph from './ToolbarOssGraph';

function OssFlow() {
  const { calculateHeight } = useConceptOptions();
  const model = useOSS();
  const controller = useOssEdit();
  const viewport = useViewport();

  console.log(controller.isMutable);

  const initialNodes: Node[] = useMemo(
    () =>
      !model.schema
        ? []
        : model.schema.items.map(operation => ({
            id: String(operation.id),
            data: { label: operation.alias },
            position: { x: operation.position_x, y: operation.position_y },
            type: operation.operation_type.toString()
          })),
    [model.schema]
  );
  // const initialNodes = [
  //   { id: '1', data: { label: '-' }, position: { x: 100, y: 100 } },
  //   { id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } }
  // ];

  const initialEdges: Edge[] = useMemo(
    () =>
      !model.schema
        ? []
        : model.schema.arguments.map((argument, index) => ({
            id: String(index),
            source: String(argument.argument),
            target: String(argument.operation)
          })),
    [model.schema]
  );
  // const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];

  const [nodes, onNodesChange] = useNodesState<Node>(initialNodes);
  const [edges, onEdgesChange] = useEdgesState<Edge>(initialEdges);

  const handleNodesChange = useCallback(
    (changes: NodeChange[]) => {
      // @ts-expect-error TODO: Figure out internal type errors in ReactFlow
      onNodesChange(changes);
    },
    [onNodesChange]
  );

  const handleEdgesChange = useCallback(
    (changes: EdgeChange[]) => {
      // @ts-expect-error TODO: Figure out internal type errors in ReactFlow
      onEdgesChange(changes);
    },
    [onEdgesChange]
  );

  const handleCreateOperation = useCallback(() => {
    // TODO: calculate insert location
    controller.promptCreateOperation(viewport.x, viewport.y);
  }, [controller, viewport]);

  const proOptions: ProOptions = { hideAttribution: true };
  const canvasWidth = useMemo(() => 'calc(100vw - 1rem)', []);
  const canvasHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);

  const OssNodeTypes: NodeTypes = useMemo(
    () => ({
      synthesis: OperationNode,
      input: InputNode
    }),
    []
  );

  return (
    <AnimateFade>
      <Overlay position='top-0 pt-1 right-1/2 translate-x-1/2' className='rounded-b-2xl cc-blur'>
        <ToolbarOssGraph onCreate={handleCreateOperation} />
      </Overlay>
      <div className='relative' style={{ height: canvasHeight, width: canvasWidth }}>
        <ReactFlow
          nodes={nodes}
          edges={edges}
          onNodesChange={handleNodesChange}
          onEdgesChange={handleEdgesChange}
          fitView
          proOptions={proOptions}
          nodeTypes={OssNodeTypes}
        />
      </div>
    </AnimateFade>
  );
}

export default OssFlow;
