import { useState, useEffect, useRef } from 'react';
import { CanvasObject } from '../../types/canvas.types';
import { sortByZIndex } from '../../utils/canvas.utils';
import Konva from 'konva';
import LayerItem from './LayerItem';

interface LayerContainerProps {
  objects: CanvasObject[];
  selectedIds: string[];
  onSelect: (ids: string[]) => void;
  onObjectsChange: (objects: CanvasObject[]) => void;
  transformerRef: React.RefObject<Konva.Transformer>;
  stageRef: React.RefObject<Konva.Stage>;
}

export default function LayerContainer({
  objects,
  selectedIds,
  onSelect,
  onObjectsChange,
  transformerRef,
  stageRef
}: LayerContainerProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [position, setPosition] = useState<{ top: number; left: number } | null>(null);
  const [draggedId, setDraggedId] = useState<string | null>(null);
  const [dropTargetIndex, setDropTargetIndex] = useState<number | null>(null);

  // Calculate position near selected object
  useEffect(() => {
    if (selectedIds.length === 0 || !transformerRef.current || !stageRef.current) {
      setPosition(null);
      return;
    }

    let animationFrameId: number | null = null;
    let lastUpdateTime = 0;
    const UPDATE_THROTTLE = 50; // Update at most every 50ms

    const updatePosition = (timestamp: number = performance.now()) => {
      const transformer = transformerRef.current;
      const stage = stageRef.current;

      if (!transformer || !stage) return;

      // Throttle updates
      if (timestamp - lastUpdateTime < UPDATE_THROTTLE) {
        animationFrameId = requestAnimationFrame(updatePosition);
        return;
      }

      lastUpdateTime = timestamp;

      const box = transformer.getClientRect();
      const container = stage.container();
      const containerRect = container.getBoundingClientRect();

      // Position to the right of the selection, with some gap
      let left = containerRect.left + box.x + box.width + 20;
      let top = containerRect.top + box.y;

      // If would go off-screen right, position to the left instead
      if (containerRef.current) {
        const layerWidth = containerRef.current.offsetWidth || 80;
        if (left + layerWidth > window.innerWidth - 20) {
          left = containerRect.left + box.x - layerWidth - 20;
        }
      }

      // Ensure it doesn't go off-screen top or bottom
      if (containerRef.current) {
        const layerHeight = containerRef.current.offsetHeight || 300;
        if (top + layerHeight > window.innerHeight - 20) {
          top = window.innerHeight - layerHeight - 20;
        }
        if (top < 20) {
          top = 20;
        }
      }

      setPosition({ top, left });
      animationFrameId = requestAnimationFrame(updatePosition);
    };

    updatePosition();

    return () => {
      if (animationFrameId !== null) {
        cancelAnimationFrame(animationFrameId);
      }
    };
  }, [selectedIds, objects, transformerRef, stageRef]);

  // Handle layer reorder
  const handleLayerReorder = (draggedId: string, targetIndex: number) => {
    const sortedByZ = sortByZIndex(objects);
    const draggedObj = objects.find(obj => obj.id === draggedId);

    if (!draggedObj) return;

    // Remove dragged object from array
    const filtered = sortedByZ.filter(obj => obj.id !== draggedId);

    // Insert at target position
    filtered.splice(targetIndex, 0, draggedObj);

    // Reassign z-index values (0 to length-1)
    const updated = filtered.map((obj, index) => ({
      ...obj,
      zIndex: index
    }));

    onObjectsChange(updated);
    setDraggedId(null);
    setDropTargetIndex(null);
  };

  // Handle layer click to select
  const handleLayerClick = (id: string, shiftKey: boolean) => {
    if (shiftKey) {
      // Add/remove from selection
      if (selectedIds.includes(id)) {
        onSelect(selectedIds.filter(selectedId => selectedId !== id));
      } else {
        onSelect([...selectedIds, id]);
      }
    } else {
      // Select only this layer
      onSelect([id]);
    }
  };

  // Handle layer name change
  const handleNameChange = (id: string, name: string) => {
    const updatedObjects = objects.map(obj =>
      obj.id === id ? { ...obj, name } : obj
    );
    onObjectsChange(updatedObjects);
  };

  if (selectedIds.length === 0 || !position) {
    return null;
  }

  // Sort objects by z-index (highest first = top of list)
  const sortedObjects = sortByZIndex(objects).reverse();

  return (
    <div
      ref={containerRef}
      className="layer-container"
      style={{
        position: 'fixed',
        top: `${position.top}px`,
        left: `${position.left}px`,
        width: '80px',
        maxHeight: '320px',
        background: 'rgba(43, 45, 49, 0.95)',
        borderRadius: '8px',
        padding: '4px',
        boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
        overflowY: 'auto',
        overflowX: 'hidden',
        zIndex: 1000,
        // Custom scrollbar
        scrollbarWidth: 'thin',
        scrollbarColor: '#b8b8b8 transparent',
        // Smooth animations
        animation: 'layerFadeIn 0.2s ease-out',
        transition: 'top 0.15s ease-out, left 0.15s ease-out'
      }}
    >
      {sortedObjects.map((obj, index) => (
        <LayerItem
          key={obj.id}
          object={obj}
          index={index}
          isSelected={selectedIds.includes(obj.id)}
          isDragging={draggedId === obj.id}
          isDropTarget={dropTargetIndex === index}
          onSelect={handleLayerClick}
          onDragStart={(id) => setDraggedId(id)}
          onDragOver={(index) => setDropTargetIndex(index)}
          onDragEnd={handleLayerReorder}
          onNameChange={handleNameChange}
        />
      ))}
    </div>
  );
}
