import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
import ReactFlow, {
  MiniMap,
  Controls,
  Background,
  useNodesState,
  useEdgesState,
  addEdge,
  Panel,
  useReactFlow,
  ReactFlowProvider,
  Handle,
  Position,
  BaseEdge,
  EdgeLabelRenderer,
  getBezierPath
} from 'reactflow';
import 'reactflow/dist/style.css';

// Import the TableCreationPopup component
import TableCreationPopup from './TableCreationPopup';

// Add custom CSS for React Flow
const generateCustomStyles = () => {
  return `
    .react-flow__node {
      z-index: 1;
      margin: 20px; /* Add margin to all nodes */
    }
    
    /* Ensure tables don't overlap */
    .react-flow__node.table-node {
      margin: 30px;
      min-height: 120px;
    }
    
    .schema-background-node {
      z-index: -1;
      pointer-events: all;
      border-radius: 25px;
      cursor: grab;
      user-select: none;
      transition: all 0.2s ease;
      padding: 30px; /* Add padding inside schema */
    }
    
    .schema-background-node:hover {
      box-shadow: 0 0 30px rgba(0, 0, 0, 0.08);
    }
    
    .schema-background-node:active {
      cursor: grabbing;
    }
    
    .schema-background-node.dragging {
      opacity: 0.8;
    }
    
    .schema-label {
      position: absolute;
      top: 20px;
      left: 20px;
      background: rgba(255, 255, 255, 0.9);
      padding: 10px 15px;
      border-radius: 8px;
      font-size: 14px;
      font-weight: bold;
      box-shadow: 0 4px 8px rgba(0,0,0,0.1);
      display: flex;
      align-items: center;
      gap: 10px;
      z-index: 10;
    }
    
    /* Ensure proper spacing between nodes */
    .react-flow__node-table {
      margin-bottom: 30px !important;
      margin-right: 30px !important;
    }
    
    /* Styling for draggable new tables */
    .draggable-new-table {
      cursor: grab !important;
      transition: all 0.2s ease !important;
      z-index: 10 !important;
    }
    
    .draggable-new-table:hover {
      transform: scale(1.02) !important;
      box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15) !important;
    }
    
    .draggable-new-table:active {
      cursor: grabbing !important;
    }
    
    /* Process node styling */
    .react-flow__node-process {
      z-index: 5 !important;
      background: white !important;
      border-radius: 8px !important;
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
    }
    
    /* Edge styling for left-to-right data flow */
    .react-flow__edge {
      z-index: 4 !important;
    }
    
    .react-flow__edge-path {
      stroke-width: 1.5 !important;
    }
    
    /* Encourage horizontal edges for left-to-right flow */
    .react-flow__edge-path {
      --react-flow-bezier-edge-control-point-distance: 60 !important;
    }
    
    /* Edge label styling */
    .react-flow__edge-textbg {
      background-color: white !important;
      padding: 2px !important;
      border-radius: 4px !important;
    }
    
    .react-flow__edge-text {
      font-size: 8px !important;
    }
  `;
};

// Import icons from react-icons
import { FaTable, FaArrowRight, FaExchangeAlt, FaFilter, FaCode, FaSync, FaCalculator, FaChartLine } from 'react-icons/fa';
import { BiSolidData, BiTransfer } from 'react-icons/bi';
import { AiFillFolder } from 'react-icons/ai';
import { TbTransform } from 'react-icons/tb';
import { CustomDatabaseIcon, CustomDocumentIcon, CustomDimensionIcon, CustomProcessIcon, CustomSchemaIcon } from './CustomIcons';

// Import API data
import mockApiData, { useApiData } from './mockData';

// Import ProcessForm component
import ProcessForm from './ProcessForm';

// Schema Background Node
const SchemaBackgroundNode = ({ data }) => {
  // Different background colors for each schema
  const bgColor = data.slug === 'edw_schema' 
    ? 'rgba(24, 144, 255, 0.1)' // Light blue for Schema_1
    : 'rgba(82, 196, 26, 0.1)';  // Light green for Schema_2
  
  // Border color based on schema
  const borderColor = data.slug === 'edw_schema' 
    ? '#1890ff' // Blue for Schema_1
    : '#52c41a';  // Green for Schema_2
  
  return (
    <div
      className="schema-background-node"
      style={{
        width: '100%',
        height: '100%',
        background: bgColor,
        border: `3px dashed ${data.color || borderColor}`,
        boxShadow: `0 0 20px rgba(0, 0, 0, 0.05)`,
        borderRadius: '25px', // Slightly larger border radius
      }}
    >
      <div className="schema-label" style={{ 
        color: data.color || borderColor,
        fontSize: '14px', // Slightly larger font
        padding: '8px 12px', // More padding
        background: 'rgba(255, 255, 255, 0.9)', // More opaque background
        boxShadow: '0 3px 6px rgba(0, 0, 0, 0.1)', // Stronger shadow
        display: 'flex',
        alignItems: 'center',
        gap: '8px'
      }}>
        <CustomSchemaIcon width="24" height="22" />
        {data.name}
      </div>
    </div>
  );
};

// Custom edge with animated arrow
const CustomEdge = ({ id, source, target, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style = {}, data, markerEnd }) => {
  // For left-to-right data flow, use a gentler curve
  const curvature = 0.2; // Reduced curvature for straighter, more horizontal flow
  
  const [edgePath, labelX, labelY] = getBezierPath({
    sourceX,
    sourceY,
    sourcePosition,
    targetX,
    targetY,
    targetPosition,
    curvature
  });

  // Check if the process is active
  const isActive = data?.isActive !== false; // Default to active if not specified
  
  // Determine if this is a source or target edge
  const isSourceEdge = data?.edgeType === 'source';
  
  // Get the process name and mappings
  const processName = data?.processName || 'Process';
  const mappings = data?.mappings || [];
  
  // Adjust label style based on active status
  const labelBgColor = isActive ? 'white' : '#f5f5f5';
  const labelOpacity = isActive ? 1 : 0.8;
  
  return (
    <>
      <BaseEdge path={edgePath} markerEnd={markerEnd} style={style} />
      <EdgeLabelRenderer>
        <div
          style={{
            position: 'absolute',
            transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
            fontSize: 10, // Reduced font size
            pointerEvents: 'all',
            backgroundColor: 'rgba(255, 255, 255, 0.9)', // Added semi-transparent background
            padding: '3px 6px',
            borderRadius: '6px',
            color: isActive ? '#333' : '#666',
            fontWeight: isActive ? 500 : 400,
            boxShadow: '0 2px 4px rgba(0,0,0,0.1)', // Added subtle shadow
            border: `1px solid ${style.stroke || '#ccc'}`,
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
            gap: '2px',
            maxWidth: '150px', // Reduced max width
            opacity: labelOpacity,
            zIndex: 4 // Lower z-index to prevent overlapping with nodes
          }}
          className="nodrag nopan"
        >
          {/* Process name in small text */}
          <div style={{ 
            fontSize: '8px', 
            color: '#666', 
            fontStyle: 'italic',
            marginBottom: '2px',
            textAlign: 'center'
          }}>
            {processName}
            {!isActive && (
              <span style={{ 
                fontSize: '7px', 
                background: '#f0f0f0', 
                padding: '0px 3px', 
                borderRadius: '3px',
                color: '#999',
                marginLeft: '2px',
                animation: "none !important"
              }}>
                inactive
              </span>
            )}
          </div>
          
          {/* Column mappings - show fewer columns to save space */}
          <div style={{ 
            display: 'flex', 
            flexWrap: 'wrap', 
            justifyContent: 'center',
            gap: '2px'
          }}>
            {mappings.length > 0 ? (
              // Only show up to 3 mappings to save space
              mappings.slice(0, 3).map((column, index) => (
                <span 
                  key={index} 
                  style={{ 
                    background: isSourceEdge 
                      ? 'rgba(82, 196, 26, 0.1)' 
                      : 'rgba(24, 144, 255, 0.1)', 
                    color: isActive 
                      ? (isSourceEdge ? '#52c41a' : '#1890ff') 
                      : '#aaaaaa',
                    padding: '1px 3px', 
                    borderRadius: '3px',
                    fontSize: '8px', // Reduced font size
                    border: `1px solid ${isActive 
                      ? (isSourceEdge ? 'rgba(82, 196, 26, 0.3)' : 'rgba(24, 144, 255, 0.3)') 
                      : 'rgba(170, 170, 170, 0.3)'}`
                  }}
                >
                  {column}
                </span>
              ))
            ) : (
              <span style={{ color: '#999', fontSize: '8px' }}>No mappings</span>
            )}
            {mappings.length > 3 && (
              <span style={{ 
                color: '#999', 
                fontSize: '8px',
                fontStyle: 'italic'
              }}>
                +{mappings.length - 3} more
              </span>
            )}
          </div>
        </div>
      </EdgeLabelRenderer>
    </>
  );
};

// Process Node (represents ETL or data transformation)
const ProcessNode = ({ data, id }) => {
  // Function to handle process edit
  const handleProcessEdit = () => {
    // Find the process in the data
    // We'll use the data that's passed to the component directly
    if (data && data.fullProcessData) {
      // We'll use window.processEditCallback which will be set in the main component
      if (window.processEditCallback) {
        window.processEditCallback(data.fullProcessData);
      }
    }
  };
  // Determine status color
  const statusColor = data.status === 'active' ? '#52c41a' : '#ff4d4f';
  const isActive = data.status === 'active';
  
  // Define colors
  const primaryColor = isActive ? '#fa8c16' : '#aaaaaa';
  const secondaryColor = isActive ? '#ff4d4f' : '#cccccc';
  
  // Determine which icon to use based on process type or other properties
  const getProcessIcon = () => {
    // You can customize this logic based on your data model
    const processType = data.processType || 'default';
    const iconSize = 40; // Reduced icon size to prevent overlapping
    const iconColor = isActive ? primaryColor : '#cccccc';
    
    switch(processType.toLowerCase()) {
      case 'transform':
        return <TbTransform size={iconSize} color={iconColor} />;
      case 'filter':
        return <FaFilter size={iconSize} color={iconColor} />;
      case 'aggregate':
        return <FaCalculator size={iconSize} color={iconColor} />;
      case 'sync':
        return <FaSync size={iconSize} color={iconColor} />;
      case 'code':
        return <FaCode size={iconSize} color={iconColor} />;
      case 'analytics':
        return <FaChartLine size={iconSize} color={iconColor} />;
      case 'transfer':
        return <BiTransfer size={iconSize} color={iconColor} />;
      case 'exchange':
        return <FaExchangeAlt size={iconSize} color={iconColor} />;
      default:
        return <CustomProcessIcon width={iconSize} height={iconSize} />;
    }
  };
  
  return (
    <div className="process-node" style={{ 
      position: 'relative',
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      justifyContent: 'center',
      background: 'white', // Add background to prevent transparency issues
      padding: '10px',
      borderRadius: '8px',
      boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)',
      border: `1px solid ${isActive ? primaryColor : '#dddddd'}`,
      width: '80px', // Fixed width to ensure consistent sizing
      height: '80px', // Fixed height to ensure consistent sizing
      zIndex: 5 // Ensure it's above the background but below other elements
    }}>
      {/* Connection handles */}
      <Handle 
        type="target" 
        position={Position.Left} 
        id="left" 
        style={{ 
          background: primaryColor, 
          width: '10px', 
          height: '10px',
          left: '-5px',
          zIndex: 10
        }} 
        isConnectable={true}
      />
      <Handle 
        type="source" 
        position={Position.Right} 
        id="right" 
        style={{ 
          background: primaryColor, 
          width: '10px', 
          height: '10px',
          right: '-5px',
          zIndex: 10
        }} 
        isConnectable={true}
      />
      
      {/* Process Icon with integrated content */}
      <div 
        onClick={handleProcessEdit}
        style={{ 
          position: 'relative',
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          filter: isActive 
            ? 'drop-shadow(0 0 8px rgba(250, 140, 22, 0.3))' 
            : 'drop-shadow(0 0 5px rgba(170, 170, 170, 0.2))',
          cursor: 'pointer',
          zIndex: 100
        }}
      >
        {getProcessIcon()}
        
        {/* Status indicator (small dot) */}
        <div style={{ 
          position: 'absolute',
          top: '-5px',
          right: '-5px',
          width: '10px',
          height: '10px',
          background: statusColor,
          borderRadius: '50%',
          border: '2px solid white'
        }} />
      </div>
      
      {/* Process Label (below icon) */}
      <div style={{ 
        fontWeight: 'bold',
        fontSize: '11px',
        color: '#333',
        textAlign: 'center',
        maxWidth: '70px',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
        marginTop: '5px',
        background: 'rgba(255, 255, 255, 0.9)',
        padding: '2px 4px',
        borderRadius: '8px'
      }}>
        {data.label}
      </div>
    </div>
  );
};

// Table Node
const TableNode = ({ data, id }) => {
  // Set up drag functionality for new tables
  const onDragStart = (event) => {
    // Only allow dragging for tables that are not in a schema yet
    if (!event.target.closest('.draggable-new-table')) {
      return;
    }
    
    event.dataTransfer.setData('application/reactflow', id);
    event.dataTransfer.effectAllowed = 'move';
  };
  // Determine table type
  const isStage = data.type === 'stage';
  const isFact = data.type === 'fact';
  const isDim = data.type === 'dimension';
  
  // Different colors for different table types
  let tableColor, tableLabel, tableIcon;
  
  if (isStage) {
    tableColor = '#fa8c16'; // Orange for STAGE tables
    tableLabel = 'STAGE';
    tableIcon = <CustomDatabaseIcon width="16" height="16" style={{ marginRight: '8px' }} />;
  } else if (isFact) {
    tableColor = '#1890ff'; // Blue for FACT tables
    tableLabel = 'FACT';
    tableIcon = <CustomDocumentIcon width="16" height="16" style={{ marginRight: '8px' }} />;
  } else {
    tableColor = '#52c41a'; // Green for DIM tables
    tableLabel = 'DIM';
    tableIcon = <CustomDimensionIcon width="16" height="16" style={{ marginRight: '8px' }} />;
  }
  
  const background = '#ffffff';
  
  return (
    <div 
      className="table-node" 
      draggable={true}
      onDragStart={onDragStart}
      style={{ 
        padding: '15px', // Increased padding
        borderRadius: '8px', // Increased border radius for better visual separation
        background: background, 
        border: `2px solid ${tableColor}`,
        width: '200px', // Slightly reduced width to allow more space between tables
        position: 'relative',
        boxShadow: `0 4px 12px rgba(0, 0, 0, 0.1)`, // Improved shadow for better depth
        color: '#333333',
        margin: '15px', // Added margin to prevent overlapping
        minHeight: '120px', // Minimum height to ensure consistent sizing
        cursor: 'grab', // Indicate draggability
      }}>
      {/* Connection handles */}
      <Handle 
        type="source" 
        position={Position.Right} 
        id="right" 
        style={{ 
          background: tableColor, 
          width: '12px', 
          height: '12px',
          right: '-6px',
          border: '2px solid white',
          zIndex: 10
        }} 
        isConnectable={true}
      />
      <Handle 
        type="target" 
        position={Position.Left} 
        id="left" 
        style={{ 
          background: tableColor, 
          width: '12px', 
          height: '12px',
          left: '-6px',
          border: '2px solid white',
          zIndex: 10
        }} 
        isConnectable={true}
      />
      
      <div style={{ 
        fontWeight: 'bold', 
        marginBottom: '10px', // Increased margin for better spacing
        display: 'flex', 
        alignItems: 'center',
        justifyContent: 'space-between' // Better alignment of elements
      }}>
        <div style={{ display: 'flex', alignItems: 'center', flex: 1, overflow: 'hidden' }}>
          {/* Different icons for different table types */}
          {tableIcon}
          <span style={{ 
            maxWidth: '110px', 
            overflow: 'hidden', 
            textOverflow: 'ellipsis', 
            whiteSpace: 'nowrap',
            fontSize: '13px' // Slightly larger font
          }}>
            {data.label}
          </span>
        </div>
        <span style={{ 
          fontSize: '10px', 
          background: tableColor, 
          color: 'white', 
          padding: '2px 6px', // Increased padding
          borderRadius: '4px', // Increased border radius
          marginLeft: '5px',
          fontWeight: 'bold'
        }}>
          {tableLabel}
        </span>
      </div>
      
      {data.columns && (
        <div style={{ 
          fontSize: '0.75em', 
          color: '#555',
          background: isStage 
            ? 'rgba(250, 140, 22, 0.1)' // Light orange for STAGE tables
            : isFact 
              ? 'rgba(24, 144, 255, 0.1)' // Light blue for FACT tables
              : 'rgba(82, 196, 26, 0.1)', // Light green for DIM tables
          padding: '8px', // Increased padding
          borderRadius: '6px', // Increased border radius
          marginTop: '8px', // Increased margin
          border: `1px solid ${isStage 
            ? 'rgba(250, 140, 22, 0.2)' 
            : isFact 
              ? 'rgba(24, 144, 255, 0.2)' 
              : 'rgba(82, 196, 26, 0.2)'}`
        }}>
          <div style={{ 
            marginBottom: '5px', 
            color: '#333', 
            fontWeight: 'bold',
            fontSize: '11px' // Slightly larger font
          }}>
            Columns:
          </div>
          <div style={{ 
            display: 'flex', 
            flexWrap: 'wrap', 
            gap: '4px' // Increased gap
          }}>
            {data.columns.slice(0, 5).map((col, index) => (
              <span key={index} style={{ 
                background: 'rgba(0, 0, 0, 0.05)', 
                padding: '2px 6px', // Increased padding
                borderRadius: '3px', // Increased border radius
                fontSize: '10px',
                color: '#333',
                border: '1px solid rgba(0, 0, 0, 0.08)' // Added subtle border
              }}>
                {col}
              </span>
            ))}
            {data.columns.length > 5 && (
              <span style={{ 
                padding: '2px 6px', // Increased padding
                fontSize: '10px',
                color: '#666',
                fontStyle: 'italic'
              }}>
                +{data.columns.length - 5} more
              </span>
            )}
          </div>
        </div>
      )}
    </div>
  );
};

const DataflowCanvas = () => {
  // React Flow refs and state
  const reactFlowWrapper = useRef(null);
  // const popupRef = useRef(null);
  const [reactFlowInstance, setReactFlowInstance] = useState(null);
  const { fitView, setViewport, getViewport } = useReactFlow();
  
  // Get data from API
  const { data: apiData, loading, error } = useApiData();
  
  // All state declarations must be at the top level
  // State for infinite canvas
  const [scale, setScale] = useState(1);
  const [position, setPosition] = useState({ x: 0, y: 0 });
  
  // State for selected database
  const [selectedDatabase, setSelectedDatabase] = useState(null);
  
  // State for connection mode
  const [isConnectionMode, setIsConnectionMode] = useState(false);
  const [connectionSource, setConnectionSource] = useState(null);
  const [connectionType, setConnectionType] = useState('default');
  
  // State for process form
  const [showProcessForm, setShowProcessForm] = useState(false);
  const [selectedProcessForEdit, setSelectedProcessForEdit] = useState(null);
  
  // State for process details popup
  const [showProcessPopup, setShowProcessPopup] = useState(false);
  const [selectedProcess, setSelectedProcess] = useState(null);
  const [popupPosition, setPopupPosition] = useState({ x: 0, y: 0 });
  
  // State for table creation popup
  const [showTablePopup, setShowTablePopup] = useState(false);
  const [isDragging, setIsDragging] = useState(false);
  const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
  
  // Read selected database from localStorage on component mount
  useEffect(() => {
    try {
      const dbData = localStorage.getItem('selectedDatabase');
      if (dbData) {
        const parsedData = JSON.parse(dbData);
        setSelectedDatabase(parsedData);
        console.log('DataFlow view initialized with database:', parsedData);
      }
    } catch (error) {
      console.error('Error reading database from localStorage:', error);
    }
  }, []);
  
  // Use API data when available
  useEffect(() => {
    if (apiData && !loading) {
      console.log('API data loaded successfully:', apiData);
    }
  }, [apiData, loading]);
  
  // Create a loading component
  const LoadingComponent = () => (
    <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
      <div>Loading data from API...</div>
    </div>
  );
  
  // Log error but continue with mockApiData as fallback
  useEffect(() => {
    if (error) {
      console.error('Error loading API data:', error);
    }
  }, [error]);
  
  // Create a loading component
  // const LoadingComponent = () => (
  //   <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
  //     <div>Loading data from API...</div>
  //   </div>
  // );
  
  // Log error but continue with mockApiData as fallback
  useEffect(() => {
    if (error) {
      console.error('Error loading API data:', error);
    }
  }, [error]);
  
  // Set up a global callback for process editing
  // This is used by the ProcessNode component
  useEffect(() => {
    window.processEditCallback = (process) => {
      setSelectedProcessForEdit(process);
      setShowProcessForm(true);
    };
    
    return () => {
      // Clean up when component unmounts
      window.processEditCallback = null;
    };
  }, []);
  
  // Define node types
  const nodeTypes = useMemo(() => ({
    table: TableNode,
    process: ProcessNode,
    schemaBackground: SchemaBackgroundNode,
  }), []);
  
  // Define edge types
  const edgeTypes = useMemo(() => ({
    custom: CustomEdge,
  }), []);

  // Create initial nodes from tables data
  const initialNodes = useMemo(() => {
    // Calculate schema boundaries based on their tables
    const schemaBoundaries = {};
    
    // Use API data when available, otherwise fall back to mock data
    const schemas = apiData?.schemas || mockApiData.schemas;
    const tables = apiData?.tables || mockApiData.tables;
    
    // Initialize with default values from schema definitions
    schemas.forEach(schema => {
      schemaBoundaries[schema.slug] = {
        minX: schema.position.x,
        minY: schema.position.y,
        maxX: schema.position.x + schema.width,
        maxY: schema.position.y + schema.height
      };
    });
    
    // Update boundaries based on table positions
    tables.forEach(table => {
      const schemaSlug = table.schema;
      if (schemaBoundaries[schemaSlug]) {
        // Add more padding around tables (250px on each side for better spacing)
        const tableMinX = table.orientation.x - 250;
        const tableMinY = table.orientation.y - 250;
        const tableMaxX = table.orientation.x + 450; // Table width + padding
        const tableMaxY = table.orientation.y + 450; // Table height + padding
        
        schemaBoundaries[schemaSlug].minX = Math.min(schemaBoundaries[schemaSlug].minX, tableMinX);
        schemaBoundaries[schemaSlug].minY = Math.min(schemaBoundaries[schemaSlug].minY, tableMinY);
        schemaBoundaries[schemaSlug].maxX = Math.max(schemaBoundaries[schemaSlug].maxX, tableMaxX);
        schemaBoundaries[schemaSlug].maxY = Math.max(schemaBoundaries[schemaSlug].maxY, tableMaxY);
      }
    });
    
    // Schema background nodes (add these first so they appear behind other nodes)
    const schemaBackgroundNodes = schemas.map(schema => {
      const bounds = schemaBoundaries[schema.slug];
      const width = bounds.maxX - bounds.minX;
      const height = bounds.maxY - bounds.minY;
      
      // Add 60% extra size for better spacing and to ensure all elements are contained
      const extraWidth = width * 0.6;
      const extraHeight = height * 0.6;
      
      return {
        id: `schema-bg-${schema.slug}`,
        type: 'schemaBackground',
        data: { 
          name: schema.name,
          color: schema.color,
          slug: schema.slug
        },
        position: { 
          x: bounds.minX - (extraWidth / 2),
          y: bounds.minY - (extraHeight / 2)
        },
        style: { 
          width: width + extraWidth,
          height: height + extraHeight,
          zIndex: -1 // Ensure it's behind other nodes
        },
        draggable: true,
        selectable: true,
        zIndex: -1,
      };
    });
    
    // Table nodes with additional spacing
    const tableNodes = tables.map(table => ({
      id: table.slug,
      type: 'table',
      data: { 
        label: table.name,
        type: table.type,
        columns: table.columns,
        slug: table.slug,
        schema: table.schema // Include schema information
      },
      position: { x: table.orientation.x, y: table.orientation.y },
      parentNode: `schema-bg-${table.schema}`, // Connect to parent schema
      extent: 'parent', // Keep within parent boundaries
      style: {
        marginBottom: '30px', // Add margin to prevent overlapping
        marginRight: '30px'   // Add margin to prevent overlapping
      },
      className: 'table-node' // Add class for styling
    }));
    
    return [...schemaBackgroundNodes, ...tableNodes];
  }, []);

  // Create process nodes
  const processNodes = useMemo(() => {
    // Use API data when available, otherwise fall back to mock data
    const processes = apiData?.processes || mockApiData.processes;
    const tables = apiData?.tables || mockApiData.tables;
    
    return processes.map((process, index) => {
      // Calculate position between source and destination tables
      const sourceTable = tables.find(t => t.slug === process.source_table[0]);
      const destTable = tables.find(t => t.slug === process.destination_table[0]);
      
      let x = 300;
      let y = 200;
      let parentSchema = null;
      
      if (sourceTable && destTable) {
        // For a left-to-right data flow, position the process node between the source and destination
        // but slightly closer to the source to maintain the flow direction
        
        // Calculate the position 1/3 of the way from source to destination
        const sourceX = sourceTable.orientation.x;
        const sourceY = sourceTable.orientation.y;
        const destX = destTable.orientation.x;
        const destY = destTable.orientation.y;
        
        // Position process node at 1/3 of the distance from source to destination
        // This creates a clearer left-to-right flow
        x = sourceX + (destX - sourceX) / 3 + 100; // Add offset to position after source table
        
        // Keep the y-coordinate aligned with the source table for a cleaner look
        // If source and destination are at different y positions, adjust slightly
        if (Math.abs(sourceY - destY) > 50) {
          // If vertical difference is significant, position between them
          y = sourceY + (destY - sourceY) / 2;
        } else {
          // Otherwise keep aligned with source
          y = sourceY;
        }
        
        // Determine which schema this process belongs to
        // If source and destination are in the same schema, use that schema
        if (sourceTable.schema === destTable.schema) {
          parentSchema = sourceTable.schema;
        } else {
          // If they're in different schemas, use the source schema
          parentSchema = sourceTable.schema;
        }
      } else if (sourceTable) {
        parentSchema = sourceTable.schema;
      } else if (destTable) {
        parentSchema = destTable.schema;
      }
      
      return {
        id: process.slug,
        type: 'process',
        data: { 
          label: process.name,
          description: process.description,
          type: process.type,
          status: process.status,
          processType: process.type, // Pass process type to the component
          fullProcessData: process // Include the full process data for editing
        },
        position: { x, y },
        parentNode: parentSchema ? `schema-bg-${parentSchema}` : undefined,
        extent: parentSchema ? 'parent' : undefined,
        style: {
          zIndex: 5, // Ensure process nodes are above edges
          margin: '20px', // Add margin to prevent overlapping
          background: 'white', // Ensure background is white
          borderRadius: '8px', // Rounded corners
          boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)' // Add shadow for better visibility
        },
        className: 'process-node' // Add class for styling
      };
    });
  }, []);

  // Create edges between tables and processes
  const initialEdges = useMemo(() => {
    const edges = [];
    
    // Use API data when available, otherwise fall back to mock data
    const processes = apiData?.processes || mockApiData.processes;
    
    processes.forEach(process => {
      // Determine if process is active or inactive
      const isActive = process.status === 'active';
      
      // Set colors and animation based on process status
      const sourceColor = isActive ? '#52c41a' : '#aaaaaa'; // Green or gray
      const destColor = isActive ? '#1890ff' : '#aaaaaa';   // Blue or gray
      const animated = isActive; // Only animate if active
      const strokeWidth = isActive ? 2 : 1.5; // Slightly thinner if inactive
      
      // Get the mappings for this process
      const mappings = process.mappings || [];
      
      // Format source columns for display
      const sourceColumns = mappings.map(m => m.source).join(', ');
      
      // Format target columns for display
      const targetColumns = mappings.map(m => m.target).join(', ');
      
      // Create edges from source tables to process
      process.source_table.forEach(sourceId => {
        edges.push({
          id: `e-${sourceId}-${process.slug}`,
          source: sourceId,
          target: process.slug,
          type: 'custom',
          animated: animated,
          style: { 
            stroke: sourceColor, 
            strokeWidth: strokeWidth,
            opacity: isActive ? 0.9 : 0.6, // Reduced opacity for better visual clarity
            zIndex: 4 // Ensure edges are below nodes
          },
          markerEnd: {
            type: 'arrowclosed',
            width: 15, // Smaller arrow
            height: 15, // Smaller arrow
            color: sourceColor,
          },
          data: {
            label: sourceColumns || 'No mappings',
            processName: process.name,
            isActive: isActive, // Pass status to the edge component
            edgeType: 'source',
            mappings: mappings.map(m => m.source)
          }
        });
      });
      
      // Create edges from process to destination tables
      process.destination_table.forEach(destId => {
        edges.push({
          id: `e-${process.slug}-${destId}`,
          source: process.slug,
          target: destId,
          type: 'custom',
          animated: animated,
          style: { 
            stroke: destColor, 
            strokeWidth: strokeWidth,
            opacity: isActive ? 0.9 : 0.6, // Reduced opacity for better visual clarity
            zIndex: 4 // Ensure edges are below nodes
          },
          markerEnd: {
            type: 'arrowclosed',
            width: 15, // Smaller arrow
            height: 15, // Smaller arrow
            color: destColor,
          },
          data: {
            label: targetColumns || 'No mappings',
            processName: process.name,
            isActive: isActive, // Pass status to the edge component
            edgeType: 'target',
            mappings: mappings.map(m => m.target)
          }
        });
      });
    });
    
    return edges;
  }, []);

  // Use React Flow's node state management
  const [nodes, setNodes, onNodesChangeDefault] = useNodesState([...initialNodes, ...processNodes]);
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
  
  // Custom nodes change handler to update schema boundaries when nodes move
  const onNodesChange = useCallback(
    (changes) => {
      // Apply the default node changes
      onNodesChangeDefault(changes);
      
      // Check if any of the changes are position changes
      const hasPositionChanges = changes.some(
        change => change.type === 'position' && change.dragging
      );
      
      // If there are position changes, force a re-render of the schema wrapper
      if (hasPositionChanges) {
        // Use a small timeout to ensure the node positions are updated first
        setTimeout(() => {
          setNodes((nds) => [...nds]);
        }, 0);
      }
    },
    [onNodesChangeDefault, setNodes]
  );

  // Track viewport changes
  const onMove = useCallback((event, viewport) => {
    setScale(viewport.zoom);
    setPosition({ x: viewport.x, y: viewport.y });
  }, []);

  const onConnect = useCallback(
    (params) => {
      // Find the source and target nodes
      const sourceNode = nodes.find(node => node.id === params.source);
      const targetNode = nodes.find(node => node.id === params.target);
      
      // Determine if this is a process connection
      let isActive = true;
      
      // Check if either source or target is a process node
      if (sourceNode?.type === 'process') {
        isActive = sourceNode.data.status === 'active';
      } else if (targetNode?.type === 'process') {
        isActive = targetNode.data.status === 'active';
      }
      
      // Create a custom edge with the selected connection type
      const edgeColor = connectionType === 'reference' ? '#00a99d' : 
                        connectionType === 'dependency' ? '#ff4d4f' : '#722ed1';
      
      // If inactive, use gray color
      const finalColor = isActive ? edgeColor : '#aaaaaa';
      
      const edgeLabel = connectionType === 'reference' ? 'references' : 
                        connectionType === 'dependency' ? 'depends on' : 'connects to';
      
      const newEdge = {
        ...params,
        id: `e-custom-${params.source}-${params.target}`,
        type: 'custom',
        animated: isActive, // Only animate if active
        style: { 
          stroke: finalColor,
          strokeWidth: isActive ? 2 : 1.5,
          opacity: isActive ? 1 : 0.7
        },
        markerEnd: {
          type: 'arrowclosed',
          width: 20,
          height: 20,
          color: finalColor,
        },
        data: {
          label: edgeLabel,
          isActive: isActive
        }
      };
      
      // Add the new edge to the edges array
      setEdges(eds => [...eds, newEdge]);
      
      // If in connection mode, exit it after creating a connection
      if (isConnectionMode) {
        setIsConnectionMode(false);
        setConnectionSource(null);
      }
      
      console.log(`Connection created: ${params.source} -> ${params.target} (${connectionType}), Active: ${isActive}`);
    },
    [setEdges, connectionType, isConnectionMode, nodes]
  );

  // Handle connection creation
  const onConnectStart = (event, params) => {
    console.log('Connection started:', params);
    setConnectionSource(params);
  };
  
  // Handle connection completion
  const onConnectEnd = (event) => {
    console.log('Connection ended');
  };

  // Initialize the flow
  const onInit = (instance) => {
    setReactFlowInstance(instance);
    
    // Set the viewport from the API data or fallback to mock data
    const viewportSettings = apiData?.viewportSettings || mockApiData.viewportSettings;
    const { x, y, zoom } = viewportSettings;
    instance.setViewport({ x, y, zoom });
    
    setTimeout(() => {
      // Use a larger padding and lower maxZoom to ensure all nodes are visible
      fitView({ padding: 1.0, maxZoom: 0.4 });
    }, 500);
  };
  const popupRef = useRef(null);
  
  // Drag handlers for the popup
  const handleMouseDown = (e) => {
    if (popupRef.current && !e.target.closest('button')) {
      const rect = popupRef.current.getBoundingClientRect();
      setIsDragging(true);
      setDragOffset({
        x: e.clientX - rect.left,
        y: e.clientY - rect.top
      });
      e.preventDefault();
    }
  };

  const handleMouseMove = (e) => {
    if (isDragging && popupRef.current) {
      const newX = e.clientX - dragOffset.x;
      const newY = e.clientY - dragOffset.y;
      
      // Keep popup within viewport bounds
      const rect = popupRef.current.getBoundingClientRect();
      const viewportWidth = window.innerWidth;
      const viewportHeight = window.innerHeight;
      
      const boundedX = Math.max(0, Math.min(newX, viewportWidth - rect.width));
      const boundedY = Math.max(0, Math.min(newY, viewportHeight - rect.height));
      
      setPopupPosition({ x: boundedX, y: boundedY });
    }
  };

  const handleMouseUp = () => {
    setIsDragging(false);
  };

  // Add and remove event listeners for dragging
  useEffect(() => {
    if (showProcessPopup) {
      window.addEventListener('mousemove', handleMouseMove);
      window.addEventListener('mouseup', handleMouseUp);
      
      return () => {
        window.removeEventListener('mousemove', handleMouseMove);
        window.removeEventListener('mouseup', handleMouseUp);
      };
    }
  }, [showProcessPopup, isDragging, dragOffset]);

  // Handle node click
  const onNodeClick = (event, node) => {
    console.log('Node clicked:', node);
    
    // Use API data when available, otherwise fall back to mock data
    const tables = apiData?.tables || mockApiData.tables;
    const processes = apiData?.processes || mockApiData.processes;
    
    // If it's a table node, show details
    if (node.type === 'table') {
      const table = tables.find(t => t.slug === node.id);
      if (table) {
        alert(`Table: ${table.name}\nType: ${table.type}\nColumns: ${table.columns.join(', ')}`);
      }
    }
    
    // If it's a process node, show details in a custom popup
    if (node.type === 'process') {
      // Use the full process data from the node data if available
      const process = node.data.fullProcessData || processes.find(p => p.slug === node.id);
      if (process) {
        // Get source and destination table names
        const sourceTables = process.source_table.map(slug => {
          const table = tables.find(t => t.slug === slug);
          return table ? table.name : slug;
        });
        
        const destTables = process.destination_table.map(slug => {
          const table = tables.find(t => t.slug === slug);
          return table ? table.name : slug;
        });
        
        // Add table names to the process object
        const processWithTableNames = {
          ...process,
          source_table_names: sourceTables,
          destination_table_names: destTables
        };
        
        setSelectedProcess(processWithTableNames);
        
        // Position the popup near the node but not directly on top of it
        const nodeElement = document.querySelector(`[data-id="${node.id}"]`);
        if (nodeElement) {
          const rect = nodeElement.getBoundingClientRect();
          setPopupPosition({ 
            x: rect.right + 20, 
            y: rect.top 
          });
        } else {
          setPopupPosition({ 
            x: event.clientX, 
            y: event.clientY 
          });
        }
        
        setShowProcessPopup(true);
      }
    }
  };
  
  // Handle edit process button click in the popup
  const handleEditProcess = (process) => {
    setSelectedProcessForEdit(process);
    setShowProcessForm(true);
    setShowProcessPopup(false);
  };

  // Show the table creation popup
  const addTableNode = () => {
    setShowTablePopup(true);
  };
  
  // Handle table creation from the popup
  const handleCreateTable = (tableData) => {
    // Generate a unique ID for the table
    const tableId = `table-${Date.now()}`;
    
    // Create the new table node
    const newTable = {
      id: tableId,
      type: 'table',
      data: { 
        label: tableData.name,
        type: tableData.type,
        columns: tableData.columns,
        slug: tableId // Add a slug for reference
      },
      // Position the table outside any schema, at the top-left corner with some margin
      position: { 
        x: 50, 
        y: 50 
      },
      // Make sure it's not initially part of any schema
      parentNode: undefined,
      extent: undefined,
      // Add draggable class to indicate it can be dragged into a schema
      className: 'table-node draggable-new-table',
      // Add styling to make it stand out
      style: {
        border: '2px dashed #1890ff',
        boxShadow: '0 0 10px rgba(24, 144, 255, 0.5)',
        zIndex: 10
      }
    };
    
    // Add the new table to the nodes
    setNodes(nodes => [...nodes, newTable]);
  };

  // Get canvas boundaries for process placement
  const getSchemasBoundaries = () => {
    // Calculate based on existing nodes
    let minX = 100;
    let minY = 100;
    let maxX = 500;
    let maxY = 500;
    
    if (nodes.length > 0) {
      minX = Math.min(...nodes.map(node => node.position.x));
      minY = Math.min(...nodes.map(node => node.position.y));
      maxX = Math.max(...nodes.map(node => node.position.x + 200)); // Assuming node width is ~200px
      maxY = Math.max(...nodes.map(node => node.position.y + 200)); // Assuming node height is ~200px
    }
    
    return { minX, minY, maxX, maxY };
  };
  
  // We don't need the moveSchemaNodes function anymore
  
  // Open the process form to create a new process
  const addProcessNode = () => {
    setSelectedProcessForEdit(null);
    setShowProcessForm(true);
  };
  
  // Handle saving a new process from the form
  const handleSaveProcess = (processData) => {
    const { minX, minY, maxX, maxY } = getSchemasBoundaries();
    
    // Place the new process outside of all schemas
    // Either to the right of all schemas or below all schemas
    let newX, newY;
    
    // Get the current viewport to help position the new node in visible area
    const viewport = reactFlowInstance ? reactFlowInstance.getViewport() : { x: 0, y: 0, zoom: 1 };
    
    // Determine placement position - right side is preferred
    newX = maxX + 200;
    newY = minY + (maxY - minY) / 2;
    
    // If we're editing an existing process, find it and update it
    if (selectedProcessForEdit) {
      const updatedNodes = nodes.map(node => {
        if (node.id === selectedProcessForEdit.slug) {
          return {
            ...node,
            data: {
              ...node.data,
              label: processData.name,
              description: processData.description,
              type: processData.type,
              status: processData.status,
              mappings: processData.mappings,
              filters: processData.filters,
              aggregations: processData.aggregations
            }
          };
        }
        return node;
      });
      
      setNodes(updatedNodes);
      
      // Update edges if source or destination tables have changed
      const processes = apiData?.processes || mockApiData.processes;
      const oldProcess = processes.find(p => p.slug === selectedProcessForEdit.slug);
      
      // Remove old edges
      if (oldProcess) {
        const edgesToRemove = edges.filter(edge => 
          edge.source === oldProcess.slug || 
          edge.target === oldProcess.slug
        );
        
        if (edgesToRemove.length > 0) {
          const remainingEdges = edges.filter(edge => 
            !edgesToRemove.some(e => e.id === edge.id)
          );
          
          setEdges(remainingEdges);
        }
      }
      
      // Create new edges
      const newEdges = [];
      
      // Determine if process is active or inactive
      const isActive = processData.status === 'active';
      
      // Set colors and animation based on process status
      const sourceColor = isActive ? '#52c41a' : '#aaaaaa'; // Green or gray
      const destColor = isActive ? '#1890ff' : '#aaaaaa';   // Blue or gray
      const animated = isActive; // Only animate if active
      const strokeWidth = isActive ? 2 : 1.5; // Slightly thinner if inactive
      const opacity = isActive ? 1 : 0.7; // Slightly transparent if inactive
      
      // Create edges from source tables to process
      processData.source_table.forEach(sourceId => {
        newEdges.push({
          id: `e-${sourceId}-${processData.slug}`,
          source: sourceId,
          target: processData.slug,
          type: 'custom',
          animated: animated,
          style: { 
            stroke: sourceColor, 
            strokeWidth: strokeWidth,
            opacity: opacity
          },
          markerEnd: {
            type: 'arrowclosed',
            width: 20,
            height: 20,
            color: sourceColor,
          },
          data: {
            label: processData.name,
            isActive: isActive
          }
        });
      });
      
      // Create edges from process to destination tables
      processData.destination_table.forEach(destId => {
        newEdges.push({
          id: `e-${processData.slug}-${destId}`,
          source: processData.slug,
          target: destId,
          type: 'custom',
          animated: animated,
          style: { 
            stroke: destColor, 
            strokeWidth: strokeWidth,
            opacity: opacity
          },
          markerEnd: {
            type: 'arrowclosed',
            width: 20,
            height: 20,
            color: destColor,
          },
          data: {
            label: processData.name,
            isActive: isActive
          }
        });
      });
      
      setEdges(eds => [...eds, ...newEdges]);
      
      // Update the data in memory
      // Note: In a real application, you would make an API call to update the data on the server
      // For now, we'll just update the mockApiData for consistency
      const processIndex = mockApiData.processes.findIndex(p => p.slug === processData.slug);
      if (processIndex !== -1) {
        mockApiData.processes[processIndex] = processData;
      }
      
      // If we have API data, update it too
      if (apiData && apiData.processes) {
        const apiProcessIndex = apiData.processes.findIndex(p => p.slug === processData.slug);
        if (apiProcessIndex !== -1) {
          apiData.processes[apiProcessIndex] = processData;
        }
      }
    } else {
      // Create a new process node
      const newProcess = {
        id: processData.slug,
        type: 'process',
        data: { 
          label: processData.name,
          description: processData.description,
          type: processData.type,
          status: processData.status,
          mappings: processData.mappings,
          filters: processData.filters,
          aggregations: processData.aggregations
        },
        position: { x: newX, y: newY },
      };
      
      setNodes(nodes => [...nodes, newProcess]);
      
      // Create edges
      const newEdges = [];
      
      // Determine if process is active or inactive
      const isActive = processData.status === 'active';
      
      // Set colors and animation based on process status
      const sourceColor = isActive ? '#52c41a' : '#aaaaaa'; // Green or gray
      const destColor = isActive ? '#1890ff' : '#aaaaaa';   // Blue or gray
      const animated = isActive; // Only animate if active
      const strokeWidth = isActive ? 2 : 1.5; // Slightly thinner if inactive
      const opacity = isActive ? 1 : 0.7; // Slightly transparent if inactive
      
      // Create edges from source tables to process
      processData.source_table.forEach(sourceId => {
        newEdges.push({
          id: `e-${sourceId}-${processData.slug}`,
          source: sourceId,
          target: processData.slug,
          type: 'custom',
          animated: animated,
          style: { 
            stroke: sourceColor, 
            strokeWidth: strokeWidth,
            opacity: opacity
          },
          markerEnd: {
            type: 'arrowclosed',
            width: 20,
            height: 20,
            color: sourceColor,
          },
          data: {
            label: processData.name,
            isActive: isActive
          }
        });
      });
      
      // Create edges from process to destination tables
      processData.destination_table.forEach(destId => {
        newEdges.push({
          id: `e-${processData.slug}-${destId}`,
          source: processData.slug,
          target: destId,
          type: 'custom',
          animated: animated,
          style: { 
            stroke: destColor, 
            strokeWidth: strokeWidth,
            opacity: opacity
          },
          markerEnd: {
            type: 'arrowclosed',
            width: 20,
            height: 20,
            color: destColor,
          },
          data: {
            label: processData.name,
            isActive: isActive
          }
        });
      });
      
      setEdges(eds => [...eds, ...newEdges]);
      
      // Add to mock data
      mockApiData.processes.push(processData);
      
      // If we have API data, update it too
      if (apiData && apiData.processes) {
        apiData.processes.push(processData);
      }
    }
  };

  // Removed schema-related functions

  // Handle dragging tables into schemas
  const onDragOver = useCallback((event) => {
    event.preventDefault();
    event.dataTransfer.dropEffect = 'move';
  }, []);

  const onDrop = useCallback((event) => {
    event.preventDefault();

    // Get the node ID from the data transfer
    const nodeId = event.dataTransfer.getData('application/reactflow');
    
    if (!nodeId || !reactFlowInstance) {
      return;
    }

    // Get the drop position
    const position = reactFlowInstance.screenToFlowPosition({
      x: event.clientX,
      y: event.clientY,
    });

    // Find the node being dragged
    const draggedNode = nodes.find(node => node.id === nodeId);
    
    if (!draggedNode) {
      return;
    }

    // Check if the drop position is within any schema
    const schemas = apiData?.schemas || mockApiData.schemas;
    let targetSchema = null;

    for (const schema of schemas) {
      const schemaNode = nodes.find(node => node.id === `schema-bg-${schema.slug}`);
      
      if (schemaNode) {
        const { x, y } = schemaNode.position;
        const { width, height } = schemaNode.style;
        
        // Check if the drop position is within this schema
        if (
          position.x >= x && 
          position.x <= x + width && 
          position.y >= y && 
          position.y <= y + height
        ) {
          targetSchema = schema;
          break;
        }
      }
    }

    // Update the node with the new position and parent schema
    const updatedNodes = nodes.map(node => {
      if (node.id === nodeId) {
        return {
          ...node,
          position,
          parentNode: targetSchema ? `schema-bg-${targetSchema.slug}` : undefined,
          extent: targetSchema ? 'parent' : undefined,
          // Remove the draggable styling
          style: {
            ...node.style,
            border: null,
            boxShadow: null
          },
          className: 'table-node'
        };
      }
      return node;
    });

    setNodes(updatedNodes);
  }, [nodes, reactFlowInstance]);

  // Add the custom CSS to the document
  useEffect(() => {
    // Create a style element
    const styleElement = document.createElement('style');
    styleElement.innerHTML = generateCustomStyles();
    document.head.appendChild(styleElement);
    
    // Clean up on unmount
    return () => {
      document.head.removeChild(styleElement);
    };
  }, []);

  // Create a style element with our custom styles
  const customStyles = useMemo(() => generateCustomStyles(), []);

  // Render the component
  return (
    <div style={{ width: '100%', height: '100%', background: '#ffffff' }} ref={reactFlowWrapper}>
      <style>{customStyles}</style>
      
      {/* Show loading state if data is still loading */}
      {loading ? (
        <LoadingComponent />
      ) : (
        <>
          {/* Database Header */}
          {selectedDatabase && (
        <div style={{
          padding: '10px 15px',
          background: 'linear-gradient(90deg, #00a99d, #52c41a)',
          color: 'white',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'space-between',
          boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)'
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
            <svg width="24" height="24" viewBox="0 0 41 39" fill="none" xmlns="http://www.w3.org/2000/svg">
              <rect width="40.5" height="38.7" rx="3.6" fill="white" fillOpacity="0.2"/>
              <path d="M19.8845 24.789C17.0714 24.789 14.2465 24.0672 12.912 22.5097C12.8725 22.683 12.8462 22.8607 12.8462 23.0493V25.8844C12.8462 28.3962 16.4937 29.5392 19.8845 29.5392C23.2753 29.5392 26.9228 28.3962 26.9228 25.8844V23.0493C26.9228 22.8607 26.8964 22.6837 26.8569 22.5104C25.5217 24.068 22.6976 24.7904 19.8837 24.7904L19.8845 24.789ZM19.8845 19.3083C17.0714 19.3083 14.2465 18.5865 12.9127 17.0289C12.8706 17.2053 12.8486 17.3858 12.8469 17.5671V20.4022C12.8469 22.9133 16.4937 24.0563 19.8845 24.0563C23.2753 24.0563 26.9228 22.9133 26.9228 20.4015V17.5657C26.9228 17.3778 26.8964 17.2001 26.8569 17.0268C25.5217 18.5843 22.6976 19.3068 19.8837 19.3068L19.8845 19.3083ZM19.8845 8.42944C16.4937 8.42944 12.8462 9.57385 12.8462 12.0857V14.9208C12.8462 17.4326 16.4937 18.5755 19.8845 18.5755C23.2753 18.5755 26.9228 17.4333 26.9228 14.9215V12.0864C26.9228 9.57458 23.2753 8.43017 19.8845 8.43017V8.42944ZM19.8845 14.2794C16.8059 14.2794 14.3087 13.2974 14.3087 12.0857C14.3087 10.8747 16.8052 9.89194 19.8845 9.89194C22.9638 9.89194 25.4603 10.8747 25.4603 12.0857C25.4603 13.2981 22.9638 14.2794 19.8845 14.2794Z" fill="white"/>
            </svg>
            <div>
              <h2 style={{ margin: 0, fontSize: '18px' }}>{selectedDatabase.name} Database</h2>
              <div style={{ fontSize: '12px', opacity: 0.9 }}>Data Flow View</div>
            </div>
          </div>
          <div>
            <button 
              onClick={() => {
                // Use hash-based routing to navigate back to explorer
                window.location.hash = '#/explorer';
                
                // Also dispatch the custom event as a fallback
                const event = new CustomEvent('switchToTab', { detail: 'canvas' });
                window.dispatchEvent(event);
              }}
              style={{
                background: 'rgba(255, 255, 255, 0.2)',
                border: 'none',
                color: 'white',
                padding: '5px 10px',
                borderRadius: '4px',
                cursor: 'pointer',
                fontSize: '12px'
              }}
            >
              Back to Explorer
            </button>
          </div>
        </div>
      )}
      
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onDrop={onDrop}
        onDragOver={onDragOver}
        onConnect={onConnect}
        onConnectStart={onConnectStart}
        onConnectEnd={onConnectEnd}
        onInit={onInit}
        onNodeClick={onNodeClick}
        onMove={onMove}
        nodeTypes={nodeTypes}
        edgeTypes={edgeTypes}
        minZoom={0.05}
        maxZoom={8}
        defaultViewport={{ x: 0, y: 0, zoom: 0.4 }}
        fitView
        fitViewOptions={{ padding: 1.0, maxZoom: 0.4 }}
        style={{ background: '#ffffff' }}
        className={isConnectionMode ? 'connection-mode' : ''}
        connectionMode="loose"
        connectionLineStyle={{
          stroke: connectionType === 'reference' ? '#00a99d' : 
                 connectionType === 'dependency' ? '#ff4d4f' : '#52c41a',
          strokeWidth: 3,
          strokeDasharray: '5,5'
        }}
        connectionLineType="bezier"
        defaultMarkerColor="#00a99d"
      >
        {/* Empty Database Message */}
        {nodes.length === 0 && selectedDatabase && (
          <Panel position="center">
            <div style={{
              background: 'rgba(255, 255, 255, 0.9)',
              padding: '30px',
              borderRadius: '8px',
              boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
              textAlign: 'center',
              maxWidth: '500px'
            }}>
              <svg width="80" height="80" viewBox="0 0 41 39" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ margin: '0 auto 20px' }}>
                <rect width="40.5" height="38.7" rx="3.6" fill="url(#db_paint0_linear)"/>
                <path d="M19.8845 24.789C17.0714 24.789 14.2465 24.0672 12.912 22.5097C12.8725 22.683 12.8462 22.8607 12.8462 23.0493V25.8844C12.8462 28.3962 16.4937 29.5392 19.8845 29.5392C23.2753 29.5392 26.9228 28.3962 26.9228 25.8844V23.0493C26.9228 22.8607 26.8964 22.6837 26.8569 22.5104C25.5217 24.068 22.6976 24.7904 19.8837 24.7904L19.8845 24.789ZM19.8845 19.3083C17.0714 19.3083 14.2465 18.5865 12.9127 17.0289C12.8706 17.2053 12.8486 17.3858 12.8469 17.5671V20.4022C12.8469 22.9133 16.4937 24.0563 19.8845 24.0563C23.2753 24.0563 26.9228 22.9133 26.9228 20.4015V17.5657C26.9228 17.3778 26.8964 17.2001 26.8569 17.0268C25.5217 18.5843 22.6976 19.3068 19.8837 19.3068L19.8845 19.3083ZM19.8845 8.42944C16.4937 8.42944 12.8462 9.57385 12.8462 12.0857V14.9208C12.8462 17.4326 16.4937 18.5755 19.8845 18.5755C23.2753 18.5755 26.9228 17.4333 26.9228 14.9215V12.0864C26.9228 9.57458 23.2753 8.43017 19.8845 8.43017V8.42944ZM19.8845 14.2794C16.8059 14.2794 14.3087 13.2974 14.3087 12.0857C14.3087 10.8747 16.8052 9.89194 19.8845 9.89194C22.9638 9.89194 25.4603 10.8747 25.4603 12.0857C25.4603 13.2981 22.9638 14.2794 19.8845 14.2794Z" fill="white"/>
                <defs>
                  <linearGradient id="db_paint0_linear" x1="40.5" y1="19.35" x2="0" y2="19.35" gradientUnits="userSpaceOnUse">
                    <stop stopColor="#006064"/>
                    <stop offset="0.711538" stopColor="#00A1A8"/>
                  </linearGradient>
                </defs>
              </svg>
              <h3 style={{ margin: '0 0 10px', color: '#333', fontSize: '20px' }}>
                {selectedDatabase.name} Database is Empty
              </h3>
              <p style={{ color: '#666', marginBottom: '20px' }}>
                This database doesn't have any tables or data flows yet. Start by adding tables and processes to visualize your data flow.
              </p>
              <div style={{ display: 'flex', justifyContent: 'center', gap: '10px' }}>
                <button 
                  onClick={() => setShowTablePopup(true)}
                  style={{
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    gap: '5px',
                    padding: '8px 16px',
                    background: '#52c41a',
                    color: 'white',
                    border: 'none',
                    borderRadius: '4px',
                    cursor: 'pointer',
                    fontSize: '14px'
                  }}
                >
                  <FaTable size={14} />
                  Add First Table
                </button>
              </div>
            </div>
          </Panel>
        )}
        
        {/* Process Details Popup */}
        {showProcessPopup && selectedProcess && (
          <div 
            ref={popupRef}
            style={{
              position: 'absolute',
              top: popupPosition.y,
              left: popupPosition.x,
              zIndex: 1000,
              background: '#ffffff',
              border: '2px solid #fa8c16',
              borderRadius: '8px',
              padding: '15px',
              boxShadow: '0 4px 20px rgba(0, 0, 0, 0.2)',
              color: '#333333',
              width: '350px',
              maxWidth: '90vw',
              maxHeight: '80vh',
              overflow: 'auto',
              backdropFilter: 'blur(5px)',
              animation: 'fadeIn 0.3s ease',
              cursor: isDragging ? 'grabbing' : 'grab',
              userSelect: 'none'
            }}
            onMouseDown={handleMouseDown}
            onClick={(e) => e.stopPropagation()}
          >
            <div style={{ 
              display: 'flex', 
              justifyContent: 'space-between', 
              alignItems: 'center',
              marginBottom: '15px',
              borderBottom: '1px solid rgba(250, 140, 22, 0.3)',
              paddingBottom: '10px',
              cursor: 'grab'
            }}
            className="popup-header"
            >
              <div style={{
                display: 'flex',
                alignItems: 'center',
                gap: '8px'
              }}>
                {/* Drag handle indicator */}
                <div style={{
                  display: 'flex',
                  flexDirection: 'column',
                  gap: '2px',
                  marginRight: '5px',
                  opacity: 0.5
                }}>
                  <div style={{ width: '20px', height: '2px', background: '#fa8c16', borderRadius: '1px' }}></div>
                  <div style={{ width: '20px', height: '2px', background: '#fa8c16', borderRadius: '1px' }}></div>
                  <div style={{ width: '20px', height: '2px', background: '#fa8c16', borderRadius: '1px' }}></div>
                </div>
                
                <h3 style={{ 
                  margin: 0, 
                  color: '#fa8c16',
                  display: 'flex',
                  alignItems: 'center',
                  gap: '8px'
                }}>
                  <CustomProcessIcon width="20" height="20" /> {selectedProcess.name}
                </h3>
              </div>
              
              <button 
                onClick={() => setShowProcessPopup(false)}
                style={{
                  background: 'transparent',
                  border: 'none',
                  color: '#666',
                  fontSize: '16px',
                  cursor: 'pointer',
                  padding: '5px'
                }}
              >
                ✕
              </button>
            </div>
            
            <div style={{ marginBottom: '15px' }}>
              <div style={{ 
                display: 'flex', 
                justifyContent: 'space-between',
                marginBottom: '8px'
              }}>
                <span style={{ color: '#666' }}>Process ID:</span>
                <span style={{ 
                  background: 'rgba(250, 140, 22, 0.1)', 
                  padding: '2px 6px', 
                  borderRadius: '4px',
                  fontFamily: 'monospace',
                  color: '#333'
                }}>
                  {selectedProcess.slug}
                </span>
              </div>
              
              <div style={{ 
                display: 'flex', 
                justifyContent: 'space-between',
                marginBottom: '8px'
              }}>
                <span style={{ color: '#666' }}>Type:</span>
                <span style={{ 
                  background: 'rgba(250, 140, 22, 0.1)', 
                  padding: '2px 6px', 
                  borderRadius: '4px',
                  color: '#333'
                }}>
                  {selectedProcess.type}
                </span>
              </div>
              
              <div style={{ 
                display: 'flex', 
                justifyContent: 'space-between',
                marginBottom: '8px'
              }}>
                <span style={{ color: '#666' }}>Status:</span>
                <span style={{ 
                  background: selectedProcess.status === 'active' ? 'rgba(82, 196, 26, 0.2)' : 'rgba(255, 77, 79, 0.2)', 
                  color: selectedProcess.status === 'active' ? '#52c41a' : '#ff4d4f',
                  padding: '2px 6px', 
                  borderRadius: '4px',
                  fontWeight: 'bold'
                }}>
                  {selectedProcess.status}
                </span>
              </div>
            </div>
            
            <div style={{ marginBottom: '15px' }}>
              <h4 style={{ 
                margin: '0 0 8px 0', 
                color: '#555',
                fontSize: '14px'
              }}>
                Description
              </h4>
              <p style={{ 
                margin: 0, 
                padding: '8px', 
                background: 'rgba(250, 140, 22, 0.05)', 
                borderRadius: '4px',
                fontSize: '14px',
                color: '#333',
                border: '1px solid rgba(250, 140, 22, 0.2)'
              }}>
                {selectedProcess.description || 'No description available'}
              </p>
            </div>
            
            <div style={{ display: 'flex', gap: '15px' }}>
              <div style={{ flex: 1 }}>
                <h4 style={{ 
                  margin: '0 0 8px 0', 
                  color: '#52c41a',
                  fontSize: '14px',
                  display: 'flex',
                  alignItems: 'center',
                  gap: '5px'
                }}>
                  <CustomDatabaseIcon width="16" height="16" /> Source Tables
                </h4>
                <ul style={{ 
                  margin: 0, 
                  padding: '8px', 
                  background: 'rgba(82, 196, 26, 0.1)', 
                  borderRadius: '4px',
                  listStyle: 'none',
                  border: '1px solid rgba(82, 196, 26, 0.2)'
                }}>
                  {selectedProcess.source_table_names.map((name, index) => (
                    <li key={index} style={{ 
                      padding: '4px 0',
                      borderBottom: index < selectedProcess.source_table_names.length - 1 ? '1px solid rgba(0, 0, 0, 0.05)' : 'none',
                      fontSize: '13px',
                      color: '#333'
                    }}>
                      {name}
                    </li>
                  ))}
                </ul>
              </div>
              
              <div style={{ flex: 1 }}>
                <h4 style={{ 
                  margin: '0 0 8px 0', 
                  color: '#1890ff',
                  fontSize: '14px',
                  display: 'flex',
                  alignItems: 'center',
                  gap: '5px'
                }}>
                  <CustomDatabaseIcon width="16" height="16" /> Destination Tables
                </h4>
                <ul style={{ 
                  margin: 0, 
                  padding: '8px', 
                  background: 'rgba(24, 144, 255, 0.1)', 
                  borderRadius: '4px',
                  listStyle: 'none',
                  border: '1px solid rgba(24, 144, 255, 0.2)'
                }}>
                  {selectedProcess.destination_table_names.map((name, index) => (
                    <li key={index} style={{ 
                      padding: '4px 0',
                      borderBottom: index < selectedProcess.destination_table_names.length - 1 ? '1px solid rgba(0, 0, 0, 0.05)' : 'none',
                      fontSize: '13px',
                      color: '#333'
                    }}>
                      {name}
                    </li>
                  ))}
                </ul>
              </div>
            </div>
            
            <div style={{ 
              marginTop: '15px', 
              display: 'flex', 
              justifyContent: 'flex-end',
              gap: '10px',
              borderTop: '1px solid rgba(250, 140, 22, 0.3)',
              paddingTop: '15px'
            }}>
              <button 
                onClick={() => setShowProcessPopup(false)}
                style={{
                  background: '#f0f0f0',
                  border: '1px solid #ccc',
                  color: '#333',
                  padding: '6px 12px',
                  borderRadius: '4px',
                  cursor: 'pointer'
                }}
              >
                Close
              </button>
              <button 
                onClick={() => handleEditProcess(selectedProcess)}
                style={{
                  background: '#fa8c16',
                  border: 'none',
                  color: '#fff',
                  padding: '6px 12px',
                  borderRadius: '4px',
                  cursor: 'pointer',
                  display: 'flex',
                  alignItems: 'center',
                  gap: '5px',
                  boxShadow: '0 2px 5px rgba(250, 140, 22, 0.3)'
                }}
              >
                <CustomProcessIcon width="16" height="16" /> Edit Process
              </button>
            </div>
          </div>
        )}
        <Controls />
        <MiniMap 
          nodeStrokeColor={(n) => {
            if (n.type === 'table') return n.data.type === 'fact' ? '#1890ff' : '#52c41a';
            return '#fa8c16';
          }}
          nodeColor={(n) => {
            if (n.type === 'table') return n.data.type === 'fact' ? 'rgba(24, 144, 255, 0.2)' : 'rgba(82, 196, 26, 0.2)';
            return 'rgba(250, 140, 22, 0.2)';
          }}
          maskColor="rgba(255, 255, 255, 0.7)"
          style={{ background: '#f0f0f0', border: '1px solid #ddd' }}
        />
        <Background color="#e0e0e0" gap={16} variant="dots" />
        
        <Panel position="top-right">
          <div style={{ 
            display: 'flex', 
            gap: '10px', 
            background: 'rgba(255, 255, 255, 0.9)', 
            padding: '10px', 
            borderRadius: '5px',
            boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
            backdropFilter: 'blur(5px)',
            border: '1px solid rgba(82, 196, 26, 0.3)',
          }}>
            <button 
              onClick={addTableNode}
              style={{
                display: 'flex',
                alignItems: 'center',
                gap: '5px',
                padding: '5px 10px',
                background: '#52c41a',
                color: 'white',
                border: 'none',
                borderRadius: '4px',
                cursor: 'pointer'
              }}
            >
              <FaTable size={14} />
              Add Table
            </button>
            <button 
              onClick={addProcessNode}
              style={{
                display: 'flex',
                alignItems: 'center',
                gap: '5px',
                padding: '5px 10px',
                background: '#fa8c16',
                color: 'white',
                border: 'none',
                borderRadius: '4px',
                cursor: 'pointer'
              }}
            >
              <CustomProcessIcon width="18" height="18" />
              Add Process
            </button>
            <button 
              onClick={() => setConnectionType(connectionType === 'default' ? 'reference' : 'default')}
              style={{
                display: 'flex',
                alignItems: 'center',
                gap: '5px',
                padding: '5px 10px',
                background: connectionType === 'reference' ? '#00a99d' : '#722ed1',
                color: 'white',
                border: 'none',
                borderRadius: '4px',
                cursor: 'pointer'
              }}
            >
              <FaExchangeAlt size={14} />
              {connectionType === 'reference' ? 'Reference' : 'Default'} Connection
            </button>
          </div>
        </Panel>
      </ReactFlow>
      
      {/* Process Form */}
      <ProcessForm 
        isOpen={showProcessForm}
        onClose={() => setShowProcessForm(false)}
        onSave={handleSaveProcess}
        tables={apiData?.tables || mockApiData.tables}
        existingProcess={selectedProcessForEdit}
      />
      
      {/* Table Creation Popup */}
      {showTablePopup && (
        <TableCreationPopup 
          onClose={() => setShowTablePopup(false)}
          onCreateTable={handleCreateTable}
        />
      )}
        </>
      )}
    </div>
  );
};

// Wrap with ReactFlowProvider
const DataflowCanvasWrapper = () => {
  return (
    <ReactFlowProvider>
      <DataflowCanvas />
    </ReactFlowProvider>
  );
};

export default DataflowCanvasWrapper;