/**
 * Workflow Builder Component
 *
 * Visual workflow editor using React Flow for creating and editing
 * Pipeline DSL configurations.
 */

import { useCallback, useRef, useEffect } from 'react';
import {
  ReactFlow,
  Controls,
  Background,
  MiniMap,
  BackgroundVariant,
  Connection,
  addEdge,
  useNodesState,
  useEdgesState,
  Node,
  NodeChange,
  EdgeChange,
  Edge,
  NodeTypes,
  ReactFlowProvider,
  useReactFlow,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';

import { useWorkflowBuilderStore, paletteCategories } from '../../store/workflowBuilderStore';
import type { WorkflowNodeData, WorkflowNodeType } from '../../lib/workflow-builder/types';

// Import custom node components
import { InputNode } from './nodes/InputNode';
import { LlmNode } from './nodes/LlmNode';
import { SkillNode } from './nodes/SkillNode';
import { HandNode } from './nodes/HandNode';
import { ConditionNode } from './nodes/ConditionNode';
import { ParallelNode } from './nodes/ParallelNode';
import { ExportNode } from './nodes/ExportNode';
import { HttpNode } from './nodes/HttpNode';
import { OrchestrationNode } from './nodes/OrchestrationNode';

import { NodePalette } from './NodePalette';
import { PropertyPanel } from './PropertyPanel';
import { WorkflowToolbar } from './WorkflowToolbar';

// =============================================================================
// Node Types Configuration
// =============================================================================

const nodeTypes: NodeTypes = {
  input: InputNode,
  llm: LlmNode,
  skill: SkillNode,
  hand: HandNode,
  condition: ConditionNode,
  parallel: ParallelNode,
  export: ExportNode,
  http: HttpNode,
  orchestration: OrchestrationNode,
};

// =============================================================================
// Main Component
// =============================================================================

export function WorkflowBuilderInternal() {
  const reactFlowWrapper = useRef<HTMLDivElement>(null);
  const { screenToFlowPosition } = useReactFlow();

  const {
    canvas,
    isDirty,
    selectedNodeId,
    validation,
    addNode,
    updateNode,
    deleteNode,
    addEdge: addStoreEdge,
    selectNode,
    saveWorkflow,
    validate,
    setDragging,
  } = useWorkflowBuilderStore();

  // Local state for React Flow
  const [nodes, setNodes, onNodesChange] = useNodesState<Node<WorkflowNodeData>>([]);
  const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>([]);

  // Sync canvas state with React Flow
  useEffect(() => {
    if (canvas) {
      setNodes(canvas.nodes.map(n => ({
        id: n.id,
        type: n.type,
        position: n.position,
        data: n.data as WorkflowNodeData,
      })));
      setEdges(canvas.edges.map(e => ({
        id: e.id,
        source: e.source,
        target: e.target,
        type: e.type || 'default',
        animated: true,
      })));
    } else {
      setNodes([]);
      setEdges([]);
    }
  }, [canvas?.id]);

  // Handle node changes (position, selection)
  const handleNodesChange = useCallback(
    (changes: NodeChange<Node<WorkflowNodeData>>[]) => {
      onNodesChange(changes);

      // Sync position changes back to store
      for (const change of changes) {
        if (change.type === 'position' && change.position) {
          const node = nodes.find(n => n.id === change.id);
          if (node) {
            // Position updates are handled by React Flow internally
          }
        }
        if (change.type === 'select') {
          selectNode(change.selected ? change.id : null);
        }
      }
    },
    [onNodesChange, nodes, selectNode]
  );

  // Handle edge changes
  const handleEdgesChange = useCallback(
    (changes: EdgeChange[]) => {
      onEdgesChange(changes);
    },
    [onEdgesChange]
  );

  // Handle new connections
  const onConnect = useCallback(
    (connection: Connection) => {
      if (connection.source && connection.target) {
        addStoreEdge(connection.source, connection.target);
        setEdges((eds) =>
          addEdge(
            {
              ...connection,
              type: 'default',
              animated: true,
            },
            eds
          )
        );
      }
    },
    [addStoreEdge, setEdges]
  );

  // Handle node click
  const onNodeClick = useCallback(
    (_event: React.MouseEvent, node: Node) => {
      selectNode(node.id);
    },
    [selectNode]
  );

  // Handle pane click (deselect)
  const onPaneClick = useCallback(() => {
    selectNode(null);
  }, [selectNode]);

  // Handle drag over for palette items
  const onDragOver = useCallback((event: React.DragEvent) => {
    event.preventDefault();
    event.dataTransfer.dropEffect = 'move';
  }, []);

  // Handle drop from palette
  const onDrop = useCallback(
    (event: React.DragEvent) => {
      event.preventDefault();

      const type = event.dataTransfer.getData('application/reactflow') as WorkflowNodeType;
      if (!type) return;

      const position = screenToFlowPosition({
        x: event.clientX,
        y: event.clientY,
      });

      addNode(type, position);
    },
    [screenToFlowPosition, addNode]
  );

  // Handle keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      // Delete selected node
      if ((event.key === 'Delete' || event.key === 'Backspace') && selectedNodeId) {
        deleteNode(selectedNodeId);
      }

      // Save workflow
      if ((event.ctrlKey || event.metaKey) && event.key === 's') {
        event.preventDefault();
        saveWorkflow();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [selectedNodeId, deleteNode, saveWorkflow]);

  if (!canvas) {
    return (
      <div className="flex items-center justify-center h-full bg-gray-50">
        <div className="text-center">
          <p className="text-gray-500 mb-4">No workflow loaded</p>
          <button
            onClick={() => useWorkflowBuilderStore.getState().createNewWorkflow('New Workflow')}
            className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
          >
            Create New Workflow
          </button>
        </div>
      </div>
    );
  }

  return (
    <div className="flex h-full">
      {/* Node Palette */}
      <NodePalette
        categories={paletteCategories}
        onDragStart={() => {
          setDragging(true);
        }}
        onDragEnd={() => {
          setDragging(false);
        }}
      />

      {/* Canvas */}
      <div className="flex-1 flex flex-col">
        <WorkflowToolbar
          workflowName={canvas.name}
          isDirty={isDirty}
          validation={validation}
          onSave={saveWorkflow}
          onValidate={validate}
        />

        <div ref={reactFlowWrapper} className="flex-1">
          <ReactFlow
            nodes={nodes}
            edges={edges}
            onNodesChange={handleNodesChange}
            onEdgesChange={handleEdgesChange}
            onConnect={onConnect}
            onNodeClick={onNodeClick}
            onPaneClick={onPaneClick}
            onDragOver={onDragOver}
            onDrop={onDrop}
            nodeTypes={nodeTypes}
            fitView
            snapToGrid
            snapGrid={[15, 15]}
            defaultEdgeOptions={{
              animated: true,
              type: 'smoothstep',
            }}
          >
            <Controls />
            <MiniMap
              nodeColor={(node) => {
                switch (node.type) {
                  case 'input':
                    return '#10b981';
                  case 'llm':
                    return '#8b5cf6';
                  case 'skill':
                    return '#f59e0b';
                  case 'hand':
                    return '#ef4444';
                  case 'export':
                    return '#3b82f6';
                  default:
                    return '#6b7280';
                }
              }}
              maskColor="rgba(0, 0, 0, 0.1)"
            />
            <Background variant={BackgroundVariant.Dots} gap={20} size={1} />
          </ReactFlow>
        </div>
      </div>

      {/* Property Panel */}
      {selectedNodeId && (
        <PropertyPanel
          nodeId={selectedNodeId}
          nodeData={nodes.find(n => n.id === selectedNodeId)?.data as WorkflowNodeData}
          onUpdate={(data) => updateNode(selectedNodeId, data)}
          onDelete={() => deleteNode(selectedNodeId)}
          onClose={() => selectNode(null)}
        />
      )}
    </div>
  );
}

// Export with provider
export function WorkflowBuilder() {
  return (
    <ReactFlowProvider>
      <WorkflowBuilderInternal />
    </ReactFlowProvider>
  );
}

export default WorkflowBuilder;
