import { useRef, useEffect, useState } from 'react';
import { Stage, Layer, Transformer, Rect, Image as KonvaImage } from 'react-konva';
import { CanvasObject, CanvasSize, CanvasBgColor, TextObject } from '../../types/canvas.types';
import { getCanvasDimensions, sortByZIndex } from '../../utils/canvas.utils';
import CanvasObjectRenderer from './CanvasObject';
import Konva from 'konva';
import useImage from 'use-image';

// Helper function to get fontStyle string based on weight and italic
function getFontStyle(bold: boolean, italic: boolean, fontWeight?: 'normal' | 'bold' | 'black'): string {
  const weight = fontWeight === 'black' ? '900' : bold ? 'bold' : 'normal';
  const style = italic ? 'italic' : '';
  return `${weight} ${style}`.trim();
}

interface CanvasProps {
  canvasSize: CanvasSize;
  bgColor: CanvasBgColor;
  objects: CanvasObject[];
  selectedIds: string[];
  onSelect: (ids: string[]) => void;
  onObjectsChange: (objects: CanvasObject[]) => void;
  textCreationMode?: boolean;
  onTextCreate?: (x: number, y: number) => void;
  stageRef?: React.RefObject<Konva.Stage>;
  transformerRef?: React.RefObject<Konva.Transformer>;
  scale?: number;
}

// Helper function to calculate cursor position from click coordinates
function calculateCursorPosition(text: string, clickX: number, fontSize: number, fontFamily: string, bold: boolean, italic: boolean, fontWeight?: 'normal' | 'bold' | 'black'): number {
  if (!text || clickX <= 0) return 0;

  try {
    const tempText = new Konva.Text({
      text: text,
      fontSize: fontSize,
      fontFamily: fontFamily,
      fontStyle: getFontStyle(bold, italic, fontWeight)
    });

    // Find the closest character position
    let closestPos = 0;
    let closestDist = Infinity;

    for (let i = 0; i <= text.length; i++) {
      const substr = text.substring(0, i);
      tempText.text(substr);
      const width = tempText.width();
      const dist = Math.abs(width - clickX);

      if (dist < closestDist) {
        closestDist = dist;
        closestPos = i;
      }
    }

    tempText.destroy();
    return closestPos;
  } catch (error) {
    console.error('Error calculating cursor position:', error);
    return text.length; // Default to end
  }
}

export default function Canvas({
  canvasSize,
  bgColor,
  objects,
  selectedIds,
  onSelect,
  onObjectsChange,
  textCreationMode = false,
  onTextCreate,
  stageRef: externalStageRef,
  transformerRef: externalTransformerRef,
  scale = 1
}: CanvasProps) {
  const internalStageRef = useRef<Konva.Stage>(null);
  const stageRef = externalStageRef || internalStageRef;
  const internalTransformerRef = useRef<Konva.Transformer>(null);
  const transformerRef = externalTransformerRef || internalTransformerRef;
  const shapeRefs = useRef<Map<string, Konva.Node>>(new Map());
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const cursorPositionRef = useRef<number | null>(null);
  const [fontsLoaded, setFontsLoaded] = useState(false);
  const [selectionBox, setSelectionBox] = useState<{ x: number; y: number; width: number; height: number } | null>(null);
  const selectionStartRef = useRef<{ x: number; y: number } | null>(null);
  const transformEndTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const dragEndTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const dragStartPositions = useRef<Map<string, { x: number; y: number }>>(new Map());
  const [hoveredId, setHoveredId] = useState<string | null>(null);
  const [isCanvasHovered, setIsCanvasHovered] = useState(false);
  const [snapGuides, setSnapGuides] = useState<{ vertical: boolean; horizontal: boolean }>({ vertical: false, horizontal: false });

  const dimensions = getCanvasDimensions(canvasSize);

  // Map canvas size to background image filename prefix
  const sizePrefix = canvasSize === '1200x675' ? 'twitter' :
                     canvasSize === 'linkedin' ? 'LinkedIn' :
                     'HF';

  // Get background image path based on bgColor and canvas size
  const getBackgroundImage = () => {
    if (bgColor === 'seriousLight') {
      return `/assets/backgrounds/bg_sLight_${sizePrefix}.png`;
    } else if (bgColor === 'light') {
      return `/assets/backgrounds/bg_Light_${sizePrefix}.png`;
    } else {
      return `/assets/backgrounds/bg_dark_${sizePrefix}.png`;
    }
  };

  const backgroundImage = getBackgroundImage();

  // Load background image with CORS enabled to allow canvas export
  const [bgImageElement] = useImage(backgroundImage, 'anonymous');

  // Wait for fonts to load before rendering
  useEffect(() => {
    const loadFonts = async () => {
      if (document.fonts) {
        try {
          // Explicitly load all fonts used in layouts
          await Promise.all([
            document.fonts.load('bold 100px Bison'),
            document.fonts.load('bold 100px Inter'),
            document.fonts.load('400 50px "IBM Plex Mono"'),
          ]);
          // Wait for all fonts to be ready
          await document.fonts.ready;
          // Add small delay to ensure fonts are fully applied
          await new Promise(resolve => setTimeout(resolve, 50));
          setFontsLoaded(true);
          // Force canvas re-render after fonts load
          if (stageRef.current) {
            const layer = stageRef.current.getLayers()[0];
            if (layer) {
              layer.batchDraw();
            }
          }
        } catch (error) {
          console.error('Font loading error:', error);
          setFontsLoaded(true);
        }
      } else {
        // Fallback for browsers without Font Loading API
        setFontsLoaded(true);
      }
    };

    loadFonts();
  }, []);

  // Force re-render when objects change and fonts are loaded
  useEffect(() => {
    if (fontsLoaded && stageRef.current) {
      const layer = stageRef.current.getLayers()[0];
      if (layer) {
        layer.batchDraw();
      }
    }
  }, [objects, fontsLoaded]);

  // Get the editing text object
  const editingText = objects.find(obj => obj.type === 'text' && obj.isEditing) as TextObject | undefined;

  // Sort objects by zIndex for proper rendering order
  const sortedObjects = sortByZIndex(objects);

  // Update transformer when selection changes or objects change
  useEffect(() => {
    if (!transformerRef.current) return;

    const attemptAttachment = (attempt: number = 0) => {
      if (selectedIds.length > 0) {
        const nodes = selectedIds
          .map(id => shapeRefs.current.get(id))
          .filter((node): node is Konva.Node => node !== undefined);

        if (nodes.length > 0) {
          transformerRef.current!.nodes(nodes);
          transformerRef.current!.show();
          transformerRef.current!.forceUpdate();
          const layer = transformerRef.current!.getLayer();
          if (layer) {
            layer.batchDraw();
          }
        } else if (attempt < 10) {
          // Retry up to 10 times with increasing delays (up to 500ms)
          const delay = Math.min(50 * (attempt + 1), 100);
          setTimeout(() => attemptAttachment(attempt + 1), delay);
        }
      } else {
        transformerRef.current!.nodes([]);
      }
    };

    // Start attempting attachment
    attemptAttachment(0);
  }, [selectedIds, objects]);

  // Handle object selection
  const handleSelect = (id: string, shiftKey: boolean = false) => {
    if (shiftKey) {
      // Shift+Click: add/remove from selection
      if (selectedIds.includes(id)) {
        // Remove from selection
        onSelect(selectedIds.filter(selectedId => selectedId !== id));
      } else {
        // Add to selection
        onSelect([...selectedIds, id]);
      }
    } else {
      // Normal click: select only this object
      onSelect([id]);
    }
  };

  // Store initial drag position for shift constraint
  const dragStartPosRef = useRef<{ x: number; y: number } | null>(null);

  // Handle drag start to store initial position(s)
  const handleDragStart = (e: Konva.KonvaEventObject<DragEvent>) => {
    const node = e.target;
    dragStartPosRef.current = { x: node.x(), y: node.y() };

    // For multi-select, store start positions of ALL selected objects
    const isMultiSelect = selectedIds.length > 1;
    if (isMultiSelect) {
      dragStartPositions.current.clear();
      selectedIds.forEach(id => {
        const objNode = shapeRefs.current.get(id);
        if (objNode) {
          dragStartPositions.current.set(id, { x: objNode.x(), y: objNode.y() });
        }
      });
    }
  };

  // Handle drag move to constrain to horizontal/vertical when Shift is held
  const handleDragMove = (e: Konva.KonvaEventObject<DragEvent>) => {
    const node = e.target;
    const shiftPressed = e.evt.shiftKey;

    // Check if multiple objects are selected
    const isMultiSelect = selectedIds.length > 1;

    // Shift key constraint - DISABLED for multi-select to prevent sticking
    // Only apply shift constraint for single object selection
    if (shiftPressed && !isMultiSelect && dragStartPosRef.current) {
      const startPos = dragStartPosRef.current;
      const currentX = node.x();
      const currentY = node.y();

      // Calculate movement deltas
      const deltaX = Math.abs(currentX - startPos.x);
      const deltaY = Math.abs(currentY - startPos.y);

      // Determine which axis to constrain
      const isHorizontal = deltaX > deltaY;

      if (isHorizontal) {
        // Horizontal movement - lock Y
        node.y(startPos.y);
      } else {
        // Vertical movement - lock X
        node.x(startPos.x);
      }
    }

    // Smart snapping to canvas center lines
    // When Shift is pressed, only snap along the unconstrained axis
    {
      const snapThreshold = 10; // pixels
      const centerX = dimensions.width / 2;
      const centerY = dimensions.height / 2;

      // Check if multiple objects are selected
      const isMultiSelect = selectedIds.length > 1;

      if (isMultiSelect) {
        // Calculate bounding box of all selected objects
        const selectedNodes = selectedIds
          .map(selectedId => shapeRefs.current.get(selectedId))
          .filter((n): n is Konva.Node => n !== undefined);

        // Only do group snapping if ALL selected nodes are available
        // This prevents rare cases where some nodes aren't registered yet
        if (selectedNodes.length === selectedIds.length && selectedNodes.length > 1) {
          // Calculate the combined bounding box
          let minX = Infinity;
          let minY = Infinity;
          let maxX = -Infinity;
          let maxY = -Infinity;

          selectedNodes.forEach(selectedNode => {
            const nodeWidth = selectedNode.width();
            const nodeHeight = selectedNode.height();
            const nodeX = selectedNode.x();
            const nodeY = selectedNode.y();

            const left = nodeX;
            const top = nodeY;
            const right = left + nodeWidth;
            const bottom = top + nodeHeight;

            minX = Math.min(minX, left);
            minY = Math.min(minY, top);
            maxX = Math.max(maxX, right);
            maxY = Math.max(maxY, bottom);
          });

          // Calculate group center
          const groupWidth = maxX - minX;
          const groupHeight = maxY - minY;
          const groupCenterX = minX + groupWidth / 2;
          const groupCenterY = minY + groupHeight / 2;

          let snapDeltaX = 0;
          let snapDeltaY = 0;
          let showVerticalGuide = false;
          let showHorizontalGuide = false;

          // Disable snapping completely when Shift is held with multi-select
          // to prevent objects getting stuck at snap points
          if (!shiftPressed) {
            // Check horizontal center snapping for the group
            if (Math.abs(groupCenterX - centerX) < snapThreshold) {
              snapDeltaX = centerX - groupCenterX;
              showVerticalGuide = true;
            }

            // Check vertical center snapping for the group
            if (Math.abs(groupCenterY - centerY) < snapThreshold) {
              snapDeltaY = centerY - groupCenterY;
              showHorizontalGuide = true;
            }
          }

          // Apply snapping by moving all selected objects by the same delta
          if (showVerticalGuide || showHorizontalGuide) {
            selectedNodes.forEach(selectedNode => {
              if (snapDeltaX !== 0) {
                selectedNode.x(selectedNode.x() + snapDeltaX);
              }
              if (snapDeltaY !== 0) {
                selectedNode.y(selectedNode.y() + snapDeltaY);
              }
            });
            setSnapGuides({ vertical: showVerticalGuide, horizontal: showHorizontalGuide });
          } else {
            setSnapGuides({ vertical: false, horizontal: false });
          }
        }
      } else {
        // Single object snapping (original logic)
        const nodeWidth = node.width();
        const nodeHeight = node.height();
        const nodeX = node.x();
        const nodeY = node.y();

        // Calculate object center position
        const objectCenterX = nodeX + (nodeWidth / 2);
        const objectCenterY = nodeY + (nodeHeight / 2);

        let snappedX = nodeX;
        let snappedY = nodeY;
        let showVerticalGuide = false;
        let showHorizontalGuide = false;

        // Determine movement direction if Shift is pressed
        let isHorizontalMovement = false;
        if (shiftPressed && dragStartPosRef.current) {
          const deltaX = Math.abs(nodeX - dragStartPosRef.current.x);
          const deltaY = Math.abs(nodeY - dragStartPosRef.current.y);
          isHorizontalMovement = deltaX > deltaY;
        }

        // Check horizontal center snapping
        // If Shift is pressed and moving vertically, don't snap horizontally
        if (Math.abs(objectCenterX - centerX) < snapThreshold && (!shiftPressed || isHorizontalMovement)) {
          snappedX = centerX - (nodeWidth / 2);
          showVerticalGuide = true;
        }

        // Check vertical center snapping
        // If Shift is pressed and moving horizontally, don't snap vertically
        if (Math.abs(objectCenterY - centerY) < snapThreshold && (!shiftPressed || !isHorizontalMovement)) {
          snappedY = centerY - (nodeHeight / 2);
          showHorizontalGuide = true;
        }

        // Apply snapping
        if (showVerticalGuide || showHorizontalGuide) {
          node.x(snappedX);
          node.y(snappedY);
          setSnapGuides({ vertical: showVerticalGuide, horizontal: showHorizontalGuide });
        } else {
          setSnapGuides({ vertical: false, horizontal: false });
        }
      }
    }
  };

  // Handle drag end to update object position
  const handleDragEnd = (id: string) => (e: Konva.KonvaEventObject<DragEvent>) => {
    const node = e.target;
    dragStartPosRef.current = null; // Reset drag start position
    dragStartPositions.current.clear(); // Clear multi-select start positions
    setSnapGuides({ vertical: false, horizontal: false }); // Clear snap guides

    // Check if multiple objects are selected
    const isMultiSelect = selectedIds.length > 1 && selectedIds.includes(id);

    if (isMultiSelect) {
      // For multi-select, debounce to ensure we only save once after all dragEnd events fire
      if (dragEndTimeoutRef.current) {
        clearTimeout(dragEndTimeoutRef.current);
      }

      dragEndTimeoutRef.current = setTimeout(() => {
        // Update ALL selected objects in a single state change
        const updatedObjects = objects.map(obj => {
          if (selectedIds.includes(obj.id)) {
            const objNode = shapeRefs.current.get(obj.id);
            if (objNode) {
              return { ...obj, x: objNode.x(), y: objNode.y() };
            }
          }
          return obj;
        });
        onObjectsChange(updatedObjects);
        dragEndTimeoutRef.current = null;
      }, 10); // Small delay to batch all dragEnd events
    } else {
      // Single object drag - update immediately
      const updatedObjects = objects.map(obj =>
        obj.id === id
          ? { ...obj, x: node.x(), y: node.y() }
          : obj
      );
      onObjectsChange(updatedObjects);
    }
  };

  // Handle transform end to update object dimensions and rotation
  const handleTransformEnd = (id: string) => (e: Konva.KonvaEventObject<Event>) => {
    const node = e.target;
    const scaleX = node.scaleX();
    const scaleY = node.scaleY();

    // Check if multiple objects are selected
    const isMultiSelect = selectedIds.length > 1;

    if (isMultiSelect) {
      // For multiselect, debounce to avoid multiple rapid updates
      // Clear any pending timeout
      if (transformEndTimeoutRef.current) {
        clearTimeout(transformEndTimeoutRef.current);
      }

      // Schedule update after a brief delay
      transformEndTimeoutRef.current = setTimeout(() => {
        // Update ALL selected objects proportionally
        const updatedObjects = objects.map(obj => {
          if (selectedIds.includes(obj.id)) {
            const objNode = shapeRefs.current.get(obj.id);
            if (objNode) {
              const nodeScaleX = objNode.scaleX();
              const nodeScaleY = objNode.scaleY();

              // Reset the node's scale
              objNode.scaleX(1);
              objNode.scaleY(1);

              const updated = {
                ...obj,
                x: objNode.x(),
                y: objNode.y(),
                width: Math.max(5, objNode.width() * nodeScaleX),
                height: Math.max(5, objNode.height() * nodeScaleY),
                rotation: objNode.rotation()
              };

              // Handle text objects: scale fontSize
              if (obj.type === 'text') {
                const scaleFactor = Math.min(nodeScaleX, nodeScaleY);
                const newFontSize = Math.max(10, obj.fontSize * scaleFactor);

                return {
                  ...updated,
                  fontSize: newFontSize,
                  isFixedSize: true
                };
              }
              return updated;
            }
          }
          return obj;
        });
        onObjectsChange(updatedObjects);
        transformEndTimeoutRef.current = null;
      }, 10);
    } else {
      // Single object transformation (original logic)
      // Reset scale to 1 and update width/height instead
      node.scaleX(1);
      node.scaleY(1);

      const updatedObjects = objects.map(obj => {
        if (obj.id === id) {
          const updated = {
            ...obj,
            x: node.x(),
            y: node.y(),
            width: Math.max(5, node.width() * scaleX),
            height: Math.max(5, node.height() * scaleY),
            rotation: node.rotation()
          };

          // Handle text objects: scale fontSize and preserve offsets
          if (obj.type === 'text') {
            // Use the smaller scale factor to maintain readability
            const scaleFactor = Math.min(scaleX, scaleY);
            const newFontSize = Math.max(10, obj.fontSize * scaleFactor);

            return {
              ...updated,
              fontSize: newFontSize,
              isFixedSize: true
            };
          }
          return updated;
        }
        return obj;
      });
      onObjectsChange(updatedObjects);
    }
  };

  // Handle text content changes
  const handleTextChange = (id: string, text: string, width: number, height: number) => {
    const updatedObjects = objects.map(obj =>
      obj.id === id && obj.type === 'text'
        ? { ...obj, text, width, height }
        : obj
    );
    onObjectsChange(updatedObjects);
  };

  // Handle editing state changes
  const handleEditingChange = (id: string, isEditing: boolean, clickX?: number, clickY?: number) => {
    // If exiting edit mode (!isEditing), check if text is empty and delete if so
    if (!isEditing) {
      const textObj = objects.find(obj => obj.id === id && obj.type === 'text') as TextObject | undefined;
      if (textObj && textObj.text.trim() === '') {
        // Text is empty - delete the object
        const updatedObjects = objects.filter(obj => obj.id !== id);
        onObjectsChange(updatedObjects);
        return;
      }
    }

    const updatedObjects = objects.map(obj =>
      obj.id === id && obj.type === 'text'
        ? { ...obj, isEditing, isFixedSize: isEditing ? obj.isFixedSize : true }
        : obj
    );
    onObjectsChange(updatedObjects);

    // Calculate cursor position if click coordinates provided
    if (isEditing && clickX !== undefined && clickY !== undefined) {
      const textObj = objects.find(obj => obj.id === id && obj.type === 'text') as TextObject | undefined;
      if (textObj) {
        const cursorPos = calculateCursorPosition(
          textObj.text,
          clickX,
          textObj.fontSize,
          textObj.fontFamily,
          textObj.bold,
          textObj.italic,
          textObj.fontWeight
        );
        cursorPositionRef.current = cursorPos;
      }
    } else if (isEditing) {
      // If no click position, set cursor to end
      cursorPositionRef.current = null;
    }
  };

  // Focus textarea when editing starts
  useEffect(() => {
    if (editingText && textareaRef.current) {
      textareaRef.current.focus();

      // Set cursor position based on click location
      if (cursorPositionRef.current !== null) {
        const pos = cursorPositionRef.current;
        textareaRef.current.setSelectionRange(pos, pos);
        cursorPositionRef.current = null; // Reset after use
      } else {
        // Default: cursor at end
        const len = textareaRef.current.value.length;
        textareaRef.current.setSelectionRange(len, len);
      }
    }
  }, [editingText?.id]);

  // Handle textarea text change
  const handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    if (!editingText) return;

    const newText = e.target.value;

    try {
      // Calculate text dimensions
      const tempText = new Konva.Text({
        text: newText || 'M',
        fontSize: editingText.fontSize,
        fontFamily: editingText.fontFamily,
        fontStyle: getFontStyle(editingText.bold, editingText.italic, editingText.fontWeight)
      });

      // Always auto-grow/shrink box while editing (live resize)
      const newWidth = Math.max(100, tempText.width() + 20);
      const newHeight = Math.max(40, tempText.height() + 10);

      tempText.destroy();
      handleTextChange(editingText.id, newText, newWidth, newHeight);
    } catch (error) {
      console.error('Error in textarea change:', error);
      handleTextChange(editingText.id, newText, editingText.width, editingText.height);
    }
  };

  // Handle textarea blur
  const handleTextareaBlur = () => {
    if (editingText) {
      handleEditingChange(editingText.id, false);
    }
  };

  // Get textarea position
  const getTextareaPosition = () => {
    if (!editingText || !stageRef.current) return { top: 0, left: 0 };

    const stage = stageRef.current;
    const container = stage.container();
    const containerRect = container.getBoundingClientRect();

    return {
      top: containerRect.top + editingText.y,
      left: containerRect.left + editingText.x
    };
  };

  const textareaPos = editingText ? getTextareaPosition() : { top: 0, left: 0 };

  // Calculate font size to fit text in fixed box (for live preview during editing)
  const calculateFitFontSize = (textObj: TextObject): number => {
    if (!textObj.isFixedSize || !textObj.text) return textObj.fontSize;

    try {
      const tempText = new Konva.Text({
        text: textObj.text,
        fontSize: textObj.fontSize,
        fontFamily: textObj.fontFamily,
        fontStyle: getFontStyle(textObj.bold, textObj.italic, textObj.fontWeight),
        width: textObj.width,
        height: textObj.height
      });

      let fontSize = textObj.fontSize;
      const maxWidth = textObj.width;
      const maxHeight = textObj.height;

      while (fontSize > 10) {
        tempText.fontSize(fontSize);
        const size = tempText.measureSize(textObj.text);

        if (size.width <= maxWidth && size.height <= maxHeight) {
          break;
        }
        fontSize -= 1;
      }

      tempText.destroy();
      return fontSize;
    } catch (error) {
      return textObj.fontSize;
    }
  };

  // Handle mouse down for selection box
  const handleMouseDown = (e: Konva.KonvaEventObject<MouseEvent>) => {
    // Only start selection box on empty canvas area
    if (e.target !== e.target.getStage()) return;

    // Don't start selection box in text creation mode
    if (textCreationMode) return;

    const stage = e.target.getStage();
    const pos = stage?.getPointerPosition();
    if (pos) {
      selectionStartRef.current = pos;
      setSelectionBox({ x: pos.x, y: pos.y, width: 0, height: 0 });
    }
  };

  // Handle mouse move for selection box
  const handleMouseMove = (e: Konva.KonvaEventObject<MouseEvent>) => {
    if (!selectionStartRef.current) return;

    const stage = e.target.getStage();
    const pos = stage?.getPointerPosition();
    if (pos) {
      const start = selectionStartRef.current;
      setSelectionBox({
        x: Math.min(start.x, pos.x),
        y: Math.min(start.y, pos.y),
        width: Math.abs(pos.x - start.x),
        height: Math.abs(pos.y - start.y)
      });
    }
  };

  // Handle mouse up for selection box
  const handleMouseUp = (e: Konva.KonvaEventObject<MouseEvent>) => {
    if (!selectionStartRef.current) {
      return;
    }

    // Check if this was a drag or just a click
    const wasDragging = selectionBox && (selectionBox.width > 5 || selectionBox.height > 5);

    if (wasDragging) {
      // Find objects within selection box
      const selected: string[] = [];
      objects.forEach(obj => {
        // Check if object intersects with selection box
        const objBox = {
          x: obj.x,
          y: obj.y,
          width: obj.width,
          height: obj.height
        };

        const boxIntersects = !(
          selectionBox.x > objBox.x + objBox.width ||
          selectionBox.x + selectionBox.width < objBox.x ||
          selectionBox.y > objBox.y + objBox.height ||
          selectionBox.y + selectionBox.height < objBox.y
        );

        if (boxIntersects) {
          selected.push(obj.id);
        }
      });

      // Update selection
      if (selected.length > 0) {
        onSelect(selected);
      } else {
        // No objects in selection box, deselect all
        onSelect([]);
      }
    } else {
      // Was a click, not a drag - deselect all
      if (e.target === e.target.getStage()) {
        onSelect([]);
      }
    }

    // Reset selection box
    selectionStartRef.current = null;
    setSelectionBox(null);
  };

  return (
    <div
      onMouseEnter={() => setIsCanvasHovered(true)}
      onMouseLeave={() => setIsCanvasHovered(false)}
      style={{
        width: dimensions.width,
        height: dimensions.height,
        backgroundImage: bgImageElement ? `url(${backgroundImage})` : 'none',
        backgroundColor: bgImageElement ? 'transparent' : '#ffffff',
        backgroundSize: 'cover',
        backgroundPosition: 'center',
        border: '1px solid #EBEBEB',
        borderRadius: isCanvasHovered ? '0px' : '10px',
        boxShadow: '0 4px 6px -2px rgba(5, 32, 81, 0.04), 0 12px 16px -4px rgba(5, 32, 81, 0.09)',
        overflow: 'hidden',
        transition: 'width 0.15s ease-in-out, height 0.15s ease-in-out, border-radius 0.15s ease-in-out'
      }}
    >
      <Stage
        ref={stageRef}
        width={dimensions.width}
        height={dimensions.height}
        onMouseDown={handleMouseDown}
        onMouseMove={handleMouseMove}
        onMouseUp={handleMouseUp}
        onClick={(e) => {
          // Check if clicking on empty canvas area
          if (e.target === e.target.getStage()) {
            if (textCreationMode && onTextCreate) {
              // Get click position relative to the stage
              const stage = e.target.getStage();
              const pointerPosition = stage?.getPointerPosition();
              if (pointerPosition) {
                onTextCreate(pointerPosition.x, pointerPosition.y);
              }
            }
            // Note: deselection is now handled in handleMouseUp
          }
        }}
        style={{ cursor: textCreationMode ? 'text' : 'default' }}
      >
        <Layer>
          {/* Background image for export */}
          {bgImageElement ? (
            <KonvaImage
              x={0}
              y={0}
              width={dimensions.width}
              height={dimensions.height}
              image={bgImageElement}
              listening={false}
            />
          ) : (
            <Rect
              x={0}
              y={0}
              width={dimensions.width}
              height={dimensions.height}
              fill="#ffffff"
              listening={false}
            />
          )}
          {sortedObjects.map((obj) => {
            return (
              <CanvasObjectRenderer
                key={obj.id}
                object={obj}
                isSelected={selectedIds.includes(obj.id)}
                onSelect={(e?: Konva.KonvaEventObject<MouseEvent>) => {
                  const shiftKey = e?.evt?.shiftKey || false;
                  handleSelect(obj.id, shiftKey);
                }}
                onDragStart={handleDragStart}
                onDragMove={handleDragMove}
                onDragEnd={handleDragEnd(obj.id)}
                onTransformEnd={handleTransformEnd(obj.id)}
                onEditingChange={handleEditingChange}
                onMouseEnter={() => setHoveredId(obj.id)}
                onMouseLeave={() => setHoveredId(null)}
                shapeRef={(node: Konva.Node | null) => {
                  if (node) {
                    shapeRefs.current.set(obj.id, node);
                  } else {
                    shapeRefs.current.delete(obj.id);
                  }
                }}
              />
            );
          })}

          {/* Selection box */}
          {selectionBox && (
            <Rect
              x={selectionBox.x}
              y={selectionBox.y}
              width={selectionBox.width}
              height={selectionBox.height}
              fill="rgba(63, 174, 230, 0.1)"
              stroke="#3faee6"
              strokeWidth={1}
              dash={[5, 5]}
              listening={false}
            />
          )}

          {/* Snap guide lines */}
          {snapGuides.vertical && (
            <Rect
              x={dimensions.width / 2}
              y={0}
              width={1}
              height={dimensions.height}
              fill="#FF6B6B"
              listening={false}
              opacity={0.8}
            />
          )}
          {snapGuides.horizontal && (
            <Rect
              x={0}
              y={dimensions.height / 2}
              width={dimensions.width}
              height={1}
              fill="#FF6B6B"
              listening={false}
              opacity={0.8}
            />
          )}

          {/* Hover bounding box - simple outline without handles */}
          {hoveredId && !selectedIds.includes(hoveredId) && (() => {
            const hoveredNode = shapeRefs.current.get(hoveredId);
            if (hoveredNode) {
              const box = hoveredNode.getClientRect();
              return (
                <Rect
                  x={box.x}
                  y={box.y}
                  width={box.width}
                  height={box.height}
                  stroke="#3faee6"
                  strokeWidth={1}
                  dash={[4, 4]}
                  listening={false}
                  opacity={0.5}
                />
              );
            }
            return null;
          })()}

          {/* Transformer for selected objects */}
          <Transformer
            ref={transformerRef}
            keepRatio={true}
            enabledAnchors={[
              'top-left',
              'top-right',
              'bottom-left',
              'bottom-right'
            ]}
            rotateEnabled={true}
            anchorSize={8}
            anchorCornerRadius={2}
            borderStroke="#3faee6"
            borderStrokeWidth={2}
            anchorStroke="#3faee6"
            anchorFill="#ffffff"
            anchorStrokeWidth={2}
            boundBoxFunc={(oldBox, newBox) => {
              // Limit minimum size
              if (newBox.width < 5 || newBox.height < 5) {
                return oldBox;
              }
              return newBox;
            }}
          />
        </Layer>
      </Stage>

      {/* Textarea for text editing - rendered outside Konva */}
      {editingText && (
        <textarea
          ref={textareaRef}
          value={editingText.text}
          onChange={handleTextareaChange}
          onBlur={handleTextareaBlur}
          onKeyDown={(e) => {
            if (e.key === 'Escape') {
              handleTextareaBlur();
            }
          }}
          style={{
            position: 'fixed',
            top: `${textareaPos.top}px`,
            left: `${textareaPos.left}px`,
            width: `${editingText.width}px`,
            height: `${editingText.height}px`,
            fontSize: `${editingText.isFixedSize ? calculateFitFontSize(editingText) : editingText.fontSize}px`,
            fontFamily: editingText.fontFamily,
            fontWeight: editingText.bold ? 'bold' : 'normal',
            fontStyle: editingText.italic ? 'italic' : 'normal',
            color: editingText.fill,
            background: 'transparent',
            border: 'none',
            borderRadius: '0',
            padding: '0',
            margin: '0',
            resize: 'none',
            outline: 'none',
            overflow: 'hidden',
            lineHeight: '1',
            verticalAlign: 'top',
            zIndex: 999,
            pointerEvents: 'auto',
            boxSizing: 'border-box'
          }}
        />
      )}
    </div>
  );
}
