'use client';

import React, { useCallback, useEffect, useState, useRef } from 'react';
import {
  ReactFlow,
  Background,
  Edge,
  Node,
  ProOptions,
  ReactFlowProvider,
  useNodesState,
  useEdgesState,
  addEdge,
  Connection,
  Controls,
  Panel,
  BackgroundVariant,
} from '@xyflow/react';

import '@xyflow/react/dist/style.css';
import './index.css';

import useLayout from './hooks/use-layout';
import nodeTypes from './node-types';
import edgeTypes from './edge-types';
import { ConditionalStep } from '@/components/agents/workflows/conditional-workflow-builder';
import { uuid } from './utils';
import { convertWorkflowToReactFlow, convertReactFlowToWorkflow } from './utils/conversion';
import { Button } from '@/components/ui/button';
import { Plus, GitBranch } from 'lucide-react';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { toast } from 'sonner';

const proOptions: ProOptions = { account: 'paid-pro', hideAttribution: true };

interface WorkflowBuilderProps {
  steps: ConditionalStep[];
  onStepsChange: (steps: ConditionalStep[]) => void;
  agentTools?: {
    agentpress_tools: Array<{ name: string; description: string; icon?: string; enabled: boolean }>;
    mcp_tools: Array<{ name: string; description: string; icon?: string; server?: string }>;
  };
  isLoadingTools?: boolean;
}

function WorkflowBuilderInner({ 
  steps, 
  onStepsChange, 
  agentTools,
  isLoadingTools 
}: WorkflowBuilderProps) {
  useLayout();
  const [nodes, setNodes, onNodesChange] = useNodesState([]);
  const [edges, setEdges, onEdgesChange] = useEdgesState([]);
  
  const onNodesChangeDebug = useCallback((changes: any) => {
    onNodesChange(changes);
  }, [onNodesChange]);
  
  const onEdgesChangeDebug = useCallback((changes: any) => {
    onEdgesChange(changes);
  }, [onEdgesChange]);

  const [isInternalUpdate, setIsInternalUpdate] = useState(false);
  const [selectedNode, setSelectedNode] = useState<string | null>(null);
  const lastConvertedSteps = useRef<string>('');
  
  useEffect(() => {
    if (!isInternalUpdate && nodes.length > 0) {
      const convertedSteps = convertReactFlowToWorkflow(nodes, edges);
      const convertedStepsStr = JSON.stringify(convertedSteps);
      if (convertedStepsStr !== lastConvertedSteps.current) {
        lastConvertedSteps.current = convertedStepsStr;
        onStepsChange(convertedSteps);
      }
    }
  }, [nodes, edges, isInternalUpdate, onStepsChange]);

  useEffect(() => {
    setIsInternalUpdate(true);
    if (steps.length > 0) {
      const { nodes: convertedNodes, edges: convertedEdges } = convertWorkflowToReactFlow(steps);
      const nodesWithTools = convertedNodes.map(node => ({
        ...node,
        data: {
          ...node.data,
          onDelete: handleNodeDelete,
          agentTools,
          isLoadingTools,
        }
      }));
      
      setNodes(nodesWithTools);
      setEdges(convertedEdges);
    } else if (nodes.length === 0) {
      const defaultNodes: Node[] = [
        {
          id: '1',
          data: { 
            name: 'Start',
            description: 'Click to add steps or use the Add Node button',
            onDelete: handleNodeDelete,
            agentTools,
            isLoadingTools,
          },
          position: { x: 0, y: 0 },
          type: 'step',
        },
      ];

      setNodes(defaultNodes);
    }
    
    setTimeout(() => {
      setIsInternalUpdate(false);
    }, 100);
  }, []);

  const onConnect = useCallback(
    (params: Connection) => setEdges((eds) => addEdge(params, eds)),
    [setEdges]
  );

  const handleNodeDelete = useCallback((nodeId: string) => {
    setNodes((nds) => nds.filter((node) => node.id !== nodeId));
    setEdges((eds) => eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId));
  }, [setNodes, setEdges]);

  const handleNodeClick = useCallback((event: React.MouseEvent, node: Node) => {
    setSelectedNode(node.id);
  }, []);

  const handlePaneClick = useCallback(() => {
    setSelectedNode(null);
  }, []);

  const addNewStep = useCallback(() => {
    console.log('=== ADDING NEW STEP ===');
    
    const newNodeId = uuid();
    
    const existingNodes = nodes;
    let position = { x: 0, y: 0 };
    let sourceNode = null;
    
    if (selectedNode) {
      sourceNode = nodes.find(n => n.id === selectedNode);
      if (sourceNode) {
        position = { x: sourceNode.position.x, y: sourceNode.position.y + 150 };
      }
    } else if (existingNodes.length > 0) {
      const bottomNode = existingNodes.reduce((prev, current) => 
        prev.position.y > current.position.y ? prev : current
      );
      sourceNode = bottomNode;
      position = { x: bottomNode.position.x, y: bottomNode.position.y + 150 };
    }
    
    const newNode: Node = {
      id: newNodeId,
      type: 'step',
      position,
      data: {
        name: 'New Step',
        description: '',
        hasIssues: true,
        onDelete: handleNodeDelete,
        agentTools,
        isLoadingTools,
      },
    };

    setNodes((nds) => {
      const newNodes = [...nds, newNode];
      return newNodes;
    });

    if (sourceNode) {
      const newEdge = {
        id: `${sourceNode.id}->${newNodeId}`,
        source: sourceNode.id,
        target: newNodeId,
        type: 'workflow',
      };
      
      setEdges((eds) => {
        const existingEdge = eds.find(e => e.id === newEdge.id);
        if (existingEdge) {
          return eds;
        }
        const newEdges = [...eds, newEdge];
        return newEdges;
      });
    }
  }, [nodes, selectedNode, handleNodeDelete, setNodes, setEdges, agentTools, isLoadingTools]);

  const addConditionBranch = useCallback((type: 'if' | 'if-else' | 'if-elseif-else') => {
    if (!selectedNode) {
      toast.error('Please select a node first to add conditions');
      return;
    }

    const sourceNode = nodes.find(n => n.id === selectedNode);
    if (!sourceNode) return;

    const conditions: Array<{ type: 'if' | 'elseif' | 'else'; id: string }> = [];
    
    if (type === 'if') {
      conditions.push({ type: 'if', id: uuid() });
    } else if (type === 'if-else') {
      conditions.push({ type: 'if', id: uuid() });
      conditions.push({ type: 'else', id: uuid() });
    } else {
      conditions.push({ type: 'if', id: uuid() });
      conditions.push({ type: 'elseif', id: uuid() });
      conditions.push({ type: 'else', id: uuid() });
    }

    const newNodes: Node[] = [];
    const newEdges: Edge[] = [];
    const xSpacing = 300;
    const startX = sourceNode.position.x - ((conditions.length - 1) * xSpacing / 2);

    conditions.forEach((condition, index) => {
      const conditionNode: Node = {
        id: condition.id,
        type: 'condition',
        position: {
          x: startX + index * xSpacing,
          y: sourceNode.position.y + 150,
        },
        data: {
          conditionType: condition.type,
          expression: condition.type !== 'else' ? '' : undefined,
          onDelete: handleNodeDelete,
        },
      };
      
      newNodes.push(conditionNode);
      
      const conditionEdge = {
        id: `${sourceNode.id}->${condition.id}`,
        source: sourceNode.id,
        target: condition.id,
        type: 'workflow',
        label: condition.type === 'if' ? 'if' :
               condition.type === 'elseif' ? 'else if' : 'else',
        labelStyle: { fill: '#666', fontSize: 12 },
        labelBgStyle: { fill: '#fff' },
      };
      
      if (!newEdges.find(e => e.id === conditionEdge.id)) {
        newEdges.push(conditionEdge);
      }
    });

    setNodes((nds) => [...nds, ...newNodes]);
    setEdges((eds) => {
      const combinedEdges = [...eds, ...newEdges];
      const uniqueEdges = combinedEdges.filter((edge, index, self) => 
        index === self.findIndex(e => e.id === edge.id)
      );
      return uniqueEdges;
    });
  }, [selectedNode, nodes, handleNodeDelete, setNodes, setEdges]);

  return (
    <div className="h-full w-full border rounded-none border-none bg-muted/10 react-flow-container">
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChangeDebug}
        onEdgesChange={onEdgesChangeDebug}
        onConnect={onConnect}
        onNodeClick={handleNodeClick}
        onPaneClick={handlePaneClick}
        proOptions={proOptions}
        fitView
        nodeTypes={nodeTypes}
        edgeTypes={edgeTypes}
        fitViewOptions={{ padding: 0.2 }}
        minZoom={0.5}
        maxZoom={1.5}
        nodesDraggable={false}
        nodesConnectable={false}
        zoomOnDoubleClick={false}
        deleteKeyCode={null}
      >
        <Background variant={BackgroundVariant.Dots} gap={16} size={1} />
        <Controls />
        <Panel position="top-left" className="react-flow__panel">
          <div className="workflow-panel-actions">
            <Button 
              variant="outline" 
              size="sm"
              onClick={addNewStep}
            >
              <Plus className="h-4 w-4" />
              Add Step
            </Button>
            <DropdownMenu>
              <DropdownMenuTrigger asChild>
                <Button variant="outline" size="sm">
                  <GitBranch className="h-4 w-4" />
                  Add Condition
                </Button>
              </DropdownMenuTrigger>
              <DropdownMenuContent>
                <DropdownMenuItem onClick={() => addConditionBranch('if')}>
                  <span className="text-xs font-mono mr-2">if</span>
                  Single condition
                </DropdownMenuItem>
                <DropdownMenuItem onClick={() => addConditionBranch('if-else')}>
                  <span className="text-xs font-mono mr-2">if-else</span>
                  Two branches
                </DropdownMenuItem>
                <DropdownMenuItem onClick={() => addConditionBranch('if-elseif-else')}>
                  <span className="text-xs font-mono mr-2">if-elif-else</span>
                  Three branches
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
          </div>
          
          {selectedNode && (
            <div className="workflow-panel-selection">
              Node selected: {nodes.find(n => n.id === selectedNode)?.data.name || selectedNode}
            </div>
          )}
        </Panel>
      </ReactFlow>
    </div>
  );
}

export function WorkflowBuilder(props: WorkflowBuilderProps) {
  return (
    <ReactFlowProvider>
      <WorkflowBuilderInner {...props} />
    </ReactFlowProvider>
  );
} 