import {Line} from "react-konva";
import {useCanvasStore} from "@/stores/canvasStore";
import type {CanvasElement, SnapGuide} from "@/types";

interface SnapGuidesProps {
  containerSize: {width: number; height: number};
}

// Snap threshold in pixels - magnetic gravitation distance
// Keep small to avoid too much jumping
const SNAP_THRESHOLD = 5;

// Center alignment threshold - just for showing helper lines, no snapping
const CENTER_ALIGN_THRESHOLD = 3;

// Calculate snap points for the stage (edges only - no center to reduce jumping)
const getStageSnapPoints = (containerSize: {
  width: number;
  height: number;
}): {vertical: number[]; horizontal: number[]} => {
  const {width, height} = containerSize;

  return {
    vertical: [0, width], // Left, right edges only
    horizontal: [0, height], // Top, bottom edges only
  };
};

// Calculate snap points for elements (edges only - no center to reduce jumping)
const getElementSnapPoints = (
  element: CanvasElement
): {vertical: number[]; horizontal: number[]} => {
  const {x, y} = element.position;
  const {width, height} = element.size;

  return {
    vertical: [x, x + width], // Left, right edges only
    horizontal: [y, y + height], // Top, bottom edges only
  };
};

// Get center points for elements (for helper lines only)
const getElementCenterPoints = (
  element: CanvasElement
): {vertical: number; horizontal: number} => {
  const {x, y} = element.position;
  const {width, height} = element.size;

  return {
    vertical: x + width / 2,
    horizontal: y + height / 2,
  };
};

// Find guides for current drag position
export const findSnapGuides = (
  draggedElement: CanvasElement,
  allElements: CanvasElement[],
  containerSize: {width: number; height: number},
  threshold: number = SNAP_THRESHOLD
): {guides: SnapGuide[]; snapPosition: {x?: number; y?: number}} => {
  const guides: SnapGuide[] = [];
  const snapPosition: {x?: number; y?: number} = {};

  const draggedPoints = getElementSnapPoints(draggedElement);
  const draggedCenter = getElementCenterPoints(draggedElement);
  const stagePoints = getStageSnapPoints(containerSize);

  // Get points from other elements (excluding dragged)
  const otherElements = allElements.filter((el) => el.id !== draggedElement.id);

  // Combine all snap targets (edges only)
  const targetVertical = [...stagePoints.vertical];
  const targetHorizontal = [...stagePoints.horizontal];

  // Collect center points for helper lines (no snapping)
  const targetCenterVertical: number[] = [containerSize.width / 2];
  const targetCenterHorizontal: number[] = [containerSize.height / 2];

  otherElements.forEach((el) => {
    const points = getElementSnapPoints(el);
    const center = getElementCenterPoints(el);
    targetVertical.push(...points.vertical);
    targetHorizontal.push(...points.horizontal);
    targetCenterVertical.push(center.vertical);
    targetCenterHorizontal.push(center.horizontal);
  });

  // Check vertical alignment (edges - with snapping)
  for (const dragPoint of draggedPoints.vertical) {
    for (const targetPoint of targetVertical) {
      const diff = Math.abs(dragPoint - targetPoint);
      if (diff < threshold) {
        // Snap!
        const offsetFromLeft = dragPoint - draggedElement.position.x;
        snapPosition.x = targetPoint - offsetFromLeft;

        guides.push({
          type: "vertical",
          position: targetPoint,
          start: 0,
          end: containerSize.height,
        });
        break;
      }
    }
    if (snapPosition.x !== undefined) break;
  }

  // Check horizontal alignment (edges - with snapping)
  for (const dragPoint of draggedPoints.horizontal) {
    for (const targetPoint of targetHorizontal) {
      const diff = Math.abs(dragPoint - targetPoint);
      if (diff < threshold) {
        // Snap!
        const offsetFromTop = dragPoint - draggedElement.position.y;
        snapPosition.y = targetPoint - offsetFromTop;

        guides.push({
          type: "horizontal",
          position: targetPoint,
          start: 0,
          end: containerSize.width,
        });
        break;
      }
    }
    if (snapPosition.y !== undefined) break;
  }

  // Check center alignment (helper lines only - no snapping)
  for (const targetCenter of targetCenterVertical) {
    const diff = Math.abs(draggedCenter.vertical - targetCenter);
    if (diff < CENTER_ALIGN_THRESHOLD) {
      guides.push({
        type: "vertical",
        position: targetCenter,
        start: 0,
        end: containerSize.height,
      });
      break;
    }
  }

  for (const targetCenter of targetCenterHorizontal) {
    const diff = Math.abs(draggedCenter.horizontal - targetCenter);
    if (diff < CENTER_ALIGN_THRESHOLD) {
      guides.push({
        type: "horizontal",
        position: targetCenter,
        start: 0,
        end: containerSize.width,
      });
      break;
    }
  }

  return {guides, snapPosition};
};

export function SnapGuides({containerSize}: SnapGuidesProps) {
  // Use individual selectors
  const showGuides = useCanvasStore((state) => state.showGuides);
  const activeGuides = useCanvasStore((state) => state.activeGuides);

  // Use activeGuides from store (set during drag)
  const guides = activeGuides;

  if (!showGuides || guides.length === 0) {
    return null;
  }

  return (
    <>
      {guides.map((guide, index) => {
        const points =
          guide.type === "vertical"
            ? [guide.position, guide.start, guide.position, guide.end]
            : [guide.start, guide.position, guide.end, guide.position];

        return (
          <Line
            key={`guide-${guide.type}-${index}`}
            points={points}
            stroke="#3b82f6"
            strokeWidth={1}
            dash={[4, 4]}
            listening={false}
          />
        );
      })}

      {/* Center crosshairs */}
      {guides.some(
        (g) => g.type === "vertical" && g.position === containerSize.width / 2
      ) && (
        <Line
          points={[
            containerSize.width / 2 - 10,
            containerSize.height / 2,
            containerSize.width / 2 + 10,
            containerSize.height / 2,
          ]}
          stroke="#ef4444"
          strokeWidth={1}
          listening={false}
        />
      )}

      {guides.some(
        (g) =>
          g.type === "horizontal" && g.position === containerSize.height / 2
      ) && (
        <Line
          points={[
            containerSize.width / 2,
            containerSize.height / 2 - 10,
            containerSize.width / 2,
            containerSize.height / 2 + 10,
          ]}
          stroke="#ef4444"
          strokeWidth={1}
          listening={false}
        />
      )}
    </>
  );
}
