import {useCallback} from "react";
import type {Stage as StageType} from "konva/lib/Stage";
import {
  useCanvasStore,
  useElements,
  useSelectedIds,
  useZoom,
  usePan,
} from "@/stores/canvasStore";
import type {Position, ElementType} from "@/types";

interface UseCanvasOptions {
  stageRef: React.RefObject<StageType | null>;
}

export function useCanvas({stageRef}: UseCanvasOptions) {
  // Use individual selectors instead of destructuring entire state
  const elements = useElements();
  const selectedIds = useSelectedIds();
  const zoom = useZoom();
  const pan = usePan();

  // Get actions directly from store (these don't cause re-renders)
  const addElement = useCanvasStore((state) => state.addElement);
  const removeElement = useCanvasStore((state) => state.removeElement);
  const clearSelection = useCanvasStore((state) => state.clearSelection);
  const moveElement = useCanvasStore((state) => state.moveElement);
  const setZoom = useCanvasStore((state) => state.setZoom);
  const setPan = useCanvasStore((state) => state.setPan);
  const saveToHistory = useCanvasStore((state) => state.saveToHistory);

  // Get pointer position relative to canvas
  const getPointerPosition = useCallback((): Position | null => {
    const stage = stageRef.current;
    if (!stage) return null;

    const pointer = stage.getPointerPosition();
    if (!pointer) return null;

    // Convert to canvas coordinates (accounting for zoom and pan)
    return {
      x: (pointer.x - pan.x) / zoom,
      y: (pointer.y - pan.y) / zoom,
    };
  }, [stageRef, zoom, pan]);

  // Add element at pointer position
  const addElementAtPointer = useCallback(
    (type: ElementType) => {
      const position = getPointerPosition() || {x: 100, y: 100};
      saveToHistory();
      addElement(type, position);
    },
    [getPointerPosition, addElement, saveToHistory]
  );

  // Add element at center of canvas
  const addElementAtCenter = useCallback(
    (type: ElementType) => {
      const stage = stageRef.current;
      if (!stage) {
        addElement(type, {x: 100, y: 100});
        return;
      }

      const centerX = (stage.width() / 2 - pan.x) / zoom;
      const centerY = (stage.height() / 2 - pan.y) / zoom;

      saveToHistory();
      addElement(type, {x: centerX - 50, y: centerY - 20});
    },
    [stageRef, zoom, pan, addElement, saveToHistory]
  );

  // Delete selected elements
  const deleteSelected = useCallback(() => {
    if (selectedIds.length === 0) return;

    saveToHistory();
    selectedIds.forEach((id) => removeElement(id));
  }, [selectedIds, removeElement, saveToHistory]);

  // Move selected elements by delta
  const moveSelectedBy = useCallback(
    (dx: number, dy: number) => {
      if (selectedIds.length === 0) return;

      saveToHistory();
      selectedIds.forEach((id) => {
        const element = elements.find((el) => el.id === id);
        if (element) {
          moveElement(id, {
            x: element.position.x + dx,
            y: element.position.y + dy,
          });
        }
      });
    },
    [selectedIds, elements, moveElement, saveToHistory]
  );

  // Zoom to fit all elements
  const zoomToFit = useCallback(() => {
    const stage = stageRef.current;
    if (!stage || elements.length === 0) return;

    // Calculate bounding box of all elements
    let minX = Infinity;
    let minY = Infinity;
    let maxX = -Infinity;
    let maxY = -Infinity;

    elements.forEach((el) => {
      minX = Math.min(minX, el.position.x);
      minY = Math.min(minY, el.position.y);
      maxX = Math.max(maxX, el.position.x + el.size.width);
      maxY = Math.max(maxY, el.position.y + el.size.height);
    });

    const padding = 50;
    const contentWidth = maxX - minX + padding * 2;
    const contentHeight = maxY - minY + padding * 2;

    const scaleX = stage.width() / contentWidth;
    const scaleY = stage.height() / contentHeight;
    const newZoom = Math.min(scaleX, scaleY, 1);

    const newPanX =
      (stage.width() - contentWidth * newZoom) / 2 -
      minX * newZoom +
      padding * newZoom;
    const newPanY =
      (stage.height() - contentHeight * newZoom) / 2 -
      minY * newZoom +
      padding * newZoom;

    setZoom(newZoom);
    setPan({x: newPanX, y: newPanY});
  }, [stageRef, elements, setZoom, setPan]);

  // Reset zoom and pan
  const resetView = useCallback(() => {
    setZoom(1);
    setPan({x: 0, y: 0});
  }, [setZoom, setPan]);

  // Keyboard shortcuts handler
  const handleKeyDown = useCallback(
    (e: KeyboardEvent) => {
      // Ignore if typing in input
      if (
        e.target instanceof HTMLInputElement ||
        e.target instanceof HTMLTextAreaElement
      ) {
        return;
      }

      const step = e.shiftKey ? 10 : 1;

      switch (e.key) {
        case "Delete":
        case "Backspace":
          e.preventDefault();
          deleteSelected();
          break;

        case "Escape":
          clearSelection();
          break;

        case "ArrowUp":
          e.preventDefault();
          moveSelectedBy(0, -step);
          break;

        case "ArrowDown":
          e.preventDefault();
          moveSelectedBy(0, step);
          break;

        case "ArrowLeft":
          e.preventDefault();
          moveSelectedBy(-step, 0);
          break;

        case "ArrowRight":
          e.preventDefault();
          moveSelectedBy(step, 0);
          break;

        case "a":
          if (e.ctrlKey || e.metaKey) {
            e.preventDefault();
            useCanvasStore.getState().selectAll();
          }
          break;

        case "0":
          if (e.ctrlKey || e.metaKey) {
            e.preventDefault();
            resetView();
          }
          break;

        case "1":
          if (e.ctrlKey || e.metaKey) {
            e.preventDefault();
            zoomToFit();
          }
          break;
      }
    },
    [deleteSelected, clearSelection, moveSelectedBy, resetView, zoomToFit]
  );

  return {
    // State
    elements,
    selectedIds,
    zoom,
    pan,

    // Position helpers
    getPointerPosition,

    // Element actions
    addElementAtPointer,
    addElementAtCenter,
    deleteSelected,
    moveSelectedBy,

    // View actions
    zoomToFit,
    resetView,

    // Keyboard handler
    handleKeyDown,
  };
}
