'use client';

import * as React from 'react';
import { cn } from '../../lib/utils';
import { DualPaneWorkspace } from '../workspace/DualPaneWorkspace';
import { WorkflowCanvas } from './WorkflowCanvas';
import { NodePalette } from './NodePalette';
import { NodeInspector } from './NodeInspector';
import {
  addEdgeToGraph,
  removeEdgesFromGraph,
  removeNodesFromGraph,
} from './graph-ops';
import type { NodeTypeDef, WfEdge, WfNode, WorkflowGraph } from './types';

export interface WorkflowEditorProps {
  /** The graph being edited (controlled when `onGraphChange` is provided). */
  graph: WorkflowGraph;
  /** Node-type catalog for the palette + canvas enrichment + inspector. */
  nodeTypes: NodeTypeDef[];
  /** Emitted with the next graph whenever the editor mutates it. */
  onGraphChange?: (graph: WorkflowGraph) => void;
  className?: string;
}

function nextNodeId(graph: WorkflowGraph): string {
  let i = graph.nodes.length + 1;
  const ids = new Set(graph.nodes.map((n) => n.id));
  while (ids.has(`node-${i}`)) i += 1;
  return `node-${i}`;
}

/**
 * Visual workflow editor: a {@link NodePalette} + interactive
 * {@link WorkflowCanvas} on the left, a JSON-Schema-driven
 * {@link NodeInspector} on the right (via {@link DualPaneWorkspace}). Manages
 * selection internally and surfaces graph mutations (rename, param edits,
 * palette add) through `onGraphChange`.
 */
export function WorkflowEditor({
  graph,
  nodeTypes,
  onGraphChange,
  className,
}: WorkflowEditorProps) {
  const [selectedId, setSelectedId] = React.useState<string | null>(null);
  const [selectedEdgeId, setSelectedEdgeId] = React.useState<string | null>(
    null
  );

  const typeIndex = React.useMemo(() => {
    const idx: Record<string, NodeTypeDef> = {};
    for (const nt of nodeTypes) idx[nt.slug] = nt;
    return idx;
  }, [nodeTypes]);

  const selectedNode = selectedId
    ? graph.nodes.find((n) => n.id === selectedId) ?? null
    : null;
  const selectedType = selectedNode ? typeIndex[selectedNode.type] : undefined;

  const handleRename = React.useCallback(
    (nodeId: string, name: string) => {
      onGraphChange?.({
        ...graph,
        nodes: graph.nodes.map((n) => (n.id === nodeId ? { ...n, name } : n)),
      });
    },
    [graph, onGraphChange]
  );

  const handleParametersChange = React.useCallback(
    (nodeId: string, parameters: Record<string, unknown>) => {
      onGraphChange?.({
        ...graph,
        nodes: graph.nodes.map((n) =>
          n.id === nodeId ? { ...n, parameters } : n
        ),
      });
    },
    [graph, onGraphChange]
  );

  const handleAddNode = React.useCallback(
    (slug: string) => {
      const def = typeIndex[slug];
      const id = nextNodeId(graph);
      const node: WfNode = {
        id,
        name: def?.name ?? slug,
        type: slug,
        parameters: {},
      };
      onGraphChange?.({ ...graph, nodes: [...graph.nodes, node] });
      setSelectedId(id);
    },
    [graph, onGraphChange, typeIndex]
  );

  const handleConnectEdge = React.useCallback(
    (edge: WfEdge) => {
      onGraphChange?.(addEdgeToGraph(graph, edge));
    },
    [graph, onGraphChange]
  );

  const handleDeleteNodes = React.useCallback(
    (nodeIds: string[]) => {
      onGraphChange?.(removeNodesFromGraph(graph, nodeIds));
      if (selectedId && nodeIds.includes(selectedId)) setSelectedId(null);
    },
    [graph, onGraphChange, selectedId]
  );

  const handleDeleteEdges = React.useCallback(
    (edges: WfEdge[]) => {
      onGraphChange?.(removeEdgesFromGraph(graph, edges));
    },
    [graph, onGraphChange]
  );

  const left = (
    <DualPaneWorkspace
      leftLabel="Nodes"
      initialLeftSize={30}
      minLeftSize={18}
      maxLeftSize={45}
      left={<NodePalette nodeTypes={nodeTypes} onAddNode={handleAddNode} />}
      right={
        <WorkflowCanvas
          graph={graph}
          nodeTypes={nodeTypes}
          onRename={handleRename}
          onSelectNode={setSelectedId}
          onSelectEdge={setSelectedEdgeId}
          selectedNodeId={selectedId}
          selectedEdgeId={selectedEdgeId}
          onDropNodeType={(slug) => handleAddNode(slug)}
          onConnectEdge={onGraphChange ? handleConnectEdge : undefined}
          onDeleteNodes={onGraphChange ? handleDeleteNodes : undefined}
          onDeleteEdges={onGraphChange ? handleDeleteEdges : undefined}
        />
      }
    />
  );

  return (
    <div className={cn('h-full min-h-0 w-full', className)}>
      <DualPaneWorkspace
        leftLabel="Editor"
        rightLabel="Inspector"
        initialLeftSize={68}
        minLeftSize={45}
        maxLeftSize={82}
        left={left}
        right={
          <NodeInspector
            node={selectedNode}
            nodeType={selectedType}
            onParametersChange={handleParametersChange}
          />
        }
      />
    </div>
  );
}
