import { html, css, svg } from 'lit';
export const connectionStyles = css`
  .connections {
    pointer-events: none;
  }
  .connections path {
    transition: stroke 0.3s ease, stroke-width 0.3s ease;
    pointer-events: all;
    cursor: pointer;
  }
  .connections path:hover {
    stroke: #999;
    stroke-width: 3;
  }
  .connections path.selected {
    stroke: #3498db;
    stroke-width: 3;
  }
  .delete-button-group {
    pointer-events: all;
    cursor: pointer;
  }
  .delete-button-group:hover .delete-button-circle {
    fill: #c0392b;
  }
  .delete-button-circle {
    fill: #e74c3c;
    transition: fill 0.2s ease;
  }
  .delete-button-x {
    stroke: white;
    stroke-width: 2;
  }
  .delete-button-group {
    pointer-events: all;
    cursor: pointer;
    /* Ensure buttons are always on top of nodes */
    z-index: 1000;
  }
`;
export const connections = function(superClass) {
  return class extends superClass {
    constructor() {
      super();
      this.connections = [];
      this.draggingConnection = null;
      this.mousePosition = { x: 0, y: 0 };
    }
    firstUpdated() {
      this.addEventListener('port-click', this._handlePortClick);
      document.addEventListener('mousemove', this._updatePreviewConnection.bind(this));
      
      document.addEventListener('click', (e) => {
        // Check if clicking on an output port
        const path = e.composedPath();
        const isOutputPort = path.some(el => 
          el instanceof HTMLElement && 
          el.classList && 
          el.classList.contains('output-ports')
        );
    
        // Only cancel connection if we're dragging AND it's not an output port
        if (this.draggingConnection && !isOutputPort) {
          // Check if we clicked on an input port
          const isInputPort = path.some(el => 
            el instanceof HTMLElement && 
            el.classList && 
            el.classList.contains('input-ports')
          );
          
          // If not an input port, cancel the connection
          if (!isInputPort) {
            this.draggingConnection = null;
            this.requestUpdate();
          }
        }
        
        // Handle existing connection deselection
        if (e.target === this.canvas) {
          this.selectedConnection = null;
          this.requestUpdate();
        }
      });
      
      super.firstUpdated();
    }
    _updatePreviewConnection(e) {
      if (this.draggingConnection) {
        this.mousePosition = {
          x: e.clientX,
          y: e.clientY
        };
        this.requestUpdate();
      }
    }
    _renderConnections() {
      const bounds = this._calculateSVGBounds();
      
      // Handle initial render when canvas is not ready
      const style = this.canvas ? `
        position: absolute; 
        top: ${bounds.minY}px; 
        left: ${bounds.minX}px; 
        width: ${bounds.width}px; 
        height: ${bounds.height}px; 
        pointer-events: none;
      ` : `
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        pointer-events: none;
      `;
    
      return html`
        
      `;
    }
    _renderPreviewConnection() {
      const sourceNode = this.nodes.find(node => node.id === this.draggingConnection.sourceNodeId);
      if (!sourceNode) return '';
      const sourcePort = sourceNode.shadowRoot.querySelector(
        `.output-ports [data-port-id="${this.draggingConnection.sourcePortId}"]`
      );
      if (!sourcePort) return '';
      const sourceRect = sourcePort.getBoundingClientRect();
      const canvasRect = this.canvas.getBoundingClientRect();
      const start = {
        x: (sourceRect.left + sourceRect.width/2 - canvasRect.left) / this.scale,
        y: (sourceRect.top + sourceRect.height/2 - canvasRect.top) / this.scale
      };
      
      const end = {
        x: (this.mousePosition.x - canvasRect.left) / this.scale,
        y: (this.mousePosition.y - canvasRect.top) / this.scale
      };
      const controlPoint1 = {
        x: start.x + Math.min(100, Math.abs(end.x - start.x) / 2),
        y: start.y
      };
      
      const controlPoint2 = {
        x: end.x - Math.min(100, Math.abs(end.x - start.x) / 2),
        y: end.y
      };
      const path = `M${start.x},${start.y} C${controlPoint1.x},${controlPoint1.y} ${controlPoint2.x},${controlPoint2.y} ${end.x},${end.y}`;
      return svg`
        
      `;
    }
    _renderConnection(conn) {
      const sourceNode = this.nodes.find(node => node.id === conn.sourceNodeId);
      const targetNode = this.nodes.find(node => node.id === conn.targetNodeId);
      
      if (!sourceNode?.shadowRoot || !targetNode?.shadowRoot) return '';
      const sourcePort = sourceNode.shadowRoot.querySelector(`.output-ports [data-port-id="${conn.sourcePortId}"]`);
      const targetPort = targetNode.shadowRoot.querySelector(`.input-ports [data-port-id="${conn.targetPortId}"]`);
      
      if (!sourcePort || !targetPort) return '';
      const sourceRect = sourcePort.getBoundingClientRect();
      const targetRect = targetPort.getBoundingClientRect();
      const canvasRect = this.canvas.getBoundingClientRect();
      const start = {
        x: (sourceRect.left + sourceRect.width/2 - canvasRect.left) / this.scale,
        y: (sourceRect.top + sourceRect.height/2 - canvasRect.top) / this.scale
      };
      
      const end = {
        x: (targetRect.left + targetRect.width/2 - canvasRect.left) / this.scale,
        y: (targetRect.top + targetRect.height/2 - canvasRect.top) / this.scale
      };
      const controlPoint1 = {
        x: start.x + Math.min(100, Math.abs(end.x - start.x) / 2),
        y: start.y
      };
      
      const controlPoint2 = {
        x: end.x - Math.min(100, Math.abs(end.x - start.x) / 2),
        y: end.y
      };
      // Helper function to get point on cubic bezier curve at t (0-1)
      const getPointOnCurve = (t) => {
        const t1 = 1 - t;
        return {
          x: Math.pow(t1, 3) * start.x +
            3 * Math.pow(t1, 2) * t * controlPoint1.x +
            3 * t1 * Math.pow(t, 2) * controlPoint2.x +
            Math.pow(t, 3) * end.x,
          y: Math.pow(t1, 3) * start.y +
            3 * Math.pow(t1, 2) * t * controlPoint1.y +
            3 * t1 * Math.pow(t, 2) * controlPoint2.y +
            Math.pow(t, 3) * end.y
        };
      };
      // Get points at 15% and 85% along the curve
      const startButton = getPointOnCurve(0.15);
      const endButton = getPointOnCurve(0.85);
      const path = `M${start.x},${start.y} C${controlPoint1.x},${controlPoint1.y} ${controlPoint2.x},${controlPoint2.y} ${end.x},${end.y}`;
      const isSelected = this.selectedConnection === conn.id;
      return svg`
        
           this._handleConnectionClick(conn.id)}"
          />
          ${isSelected ? svg`
            
              
               this._deleteConnection(conn.id)}">
                
                
              
              
               this._deleteConnection(conn.id)}">
                
                
              
            
          ` : ''}
        
      `;
    }
    _handleConnectionClick(connectionId) {
      // Deselect if clicking the same connection
      if (this.selectedConnection === connectionId) {
        this.selectedConnection = null;
      } else {
        this.selectedConnection = connectionId;
      }
      this.requestUpdate();
    }
    _deleteConnection(connectionId) {
      const connection = this.connections.find(conn => conn.id === connectionId);
      this.connections = this.connections.filter(conn => conn.id !== connectionId);
      this.selectedConnection = null;
      if (connection) {
        this._dispatchChangeEvent({
          type: 'connection-removed',
          data: { connectionId }
        });
      }
      this.requestUpdate();
    }
    _handlePortClick(e) {
      const { nodeId, portType, portId, portName } = e.detail;
      
      if (!this.draggingConnection) {
        if (portType === 'output') {
          this.draggingConnection = {
            sourceNodeId: nodeId,
            sourcePortId: portId,
            sourcePortType: portType
          };
        }
      } else {
        if (portType === 'input' && nodeId !== this.draggingConnection.sourceNodeId) {
          const connectionExists = this.connections.some(conn => 
            conn.sourceNodeId === this.draggingConnection.sourceNodeId && 
            conn.sourcePortId === this.draggingConnection.sourcePortId &&
            conn.targetNodeId === nodeId &&
            conn.targetPortId === portId
          );
          if (!connectionExists) {
            const connection = {
              id: `conn_${Date.now()}`,
              sourceNodeId: this.draggingConnection.sourceNodeId,
              sourcePortId: this.draggingConnection.sourcePortId,
              targetNodeId: nodeId,
              targetPortId: portId
            };
            
            this.connections = [...this.connections, connection];
            this._dispatchChangeEvent({
              type: 'connection-added',
              data: connection
            });
          }
        }
        this.draggingConnection = null;
        this.requestUpdate();
      }
    }
    _calculateSVGBounds() {
      // If canvas is not ready yet, return default bounds
      if (!this.canvas) {
        return {
          minX: 0,
          minY: 0,
          width: '100%',
          height: '100%'
        };
      }
    
      let minX = 0, minY = 0, maxX = 0, maxY = 0;
      const canvasRect = this.canvas.getBoundingClientRect();
    
      // Include all node positions
      this.nodes.forEach(node => {
        const rect = node.getBoundingClientRect();
        minX = Math.min(minX, (rect.left - canvasRect.left) / this.scale);
        minY = Math.min(minY, (rect.top - canvasRect.top) / this.scale);
        maxX = Math.max(maxX, (rect.right - canvasRect.left) / this.scale);
        maxY = Math.max(maxY, (rect.bottom - canvasRect.top) / this.scale);
      });
    
      const padding = 1000;
      return {
        minX: minX - padding,
        minY: minY - padding,
        width: maxX - minX + (padding * 2),
        height: maxY - minY + (padding * 2)
      };
    }
  };
}